diff -Nru ukui-biometric-auth-4.10.0.0/debian/changelog ukui-biometric-auth-4.10.0.0/debian/changelog
--- ukui-biometric-auth-4.10.0.0/debian/changelog	2024-11-15 16:52:41.000000000 +0800
+++ ukui-biometric-auth-4.10.0.0/debian/changelog	2025-02-13 20:57:03.000000000 +0800
@@ -1,3 +1,12 @@
+ukui-biometric-auth (4.10.0.0-ok12) nile; urgency=medium
+
+  * BUG号:无
+  * 需求号:无
+  * 其他改动说明:同步V11-2503代码
+  * 其他改动影响域:无
+
+ -- Yang Min <yangmin@kylinos.cn>  Thu, 13 Feb 2025 20:57:03 +0800
+
 ukui-biometric-auth (4.10.0.0-ok11) nile; urgency=medium
 
   * BUG号:#IB4M9L 修改密码等需要授权认证的操作直接失败,无法打开提权窗口
diff -Nru ukui-biometric-auth-4.10.0.0/debian/patches/0030-update-changelog.patch ukui-biometric-auth-4.10.0.0/debian/patches/0030-update-changelog.patch
--- ukui-biometric-auth-4.10.0.0/debian/patches/0030-update-changelog.patch	1970-01-01 08:00:00.000000000 +0800
+++ ukui-biometric-auth-4.10.0.0/debian/patches/0030-update-changelog.patch	2025-02-13 20:57:03.000000000 +0800
@@ -0,0 +1,10516 @@
+From: yangmin100 <yangmin@kylinos.cn>
+Date: Thu, 13 Feb 2025 20:58:19 +0800
+Subject: update changelog
+
+---
+ tests/CMakeLists.txt                              |   42 +
+ tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp  |   58 +
+ tests/kt-test-utils/cpp-stub-ext/stub-shadow.h    |  171 +
+ tests/kt-test-utils/cpp-stub-ext/stubext.h        |  129 +
+ tests/kt-test-utils/cpp-stub/addr_any.h           |  280 ++
+ tests/kt-test-utils/cpp-stub/addr_pri.h           |  177 +
+ tests/kt-test-utils/cpp-stub/elfio.hpp            | 4888 +++++++++++++++++++++
+ tests/kt-test-utils/cpp-stub/stub.h               |  360 ++
+ tests/unit_test_biodeviceinfo/CMakeLists.txt      |   58 +
+ tests/unit_test_biodeviceinfo/main.cpp            |   49 +
+ tests/unit_test_biodevices/CMakeLists.txt         |   76 +
+ tests/unit_test_biodevices/main.cpp               |  114 +
+ tests/unit_test_common/CMakeLists.txt             |   60 +
+ tests/unit_test_common/main.cpp                   |   12 +
+ tests/unit_test_common/unit_test_common.cpp       |   29 +
+ tests/unit_test_giodbus/CMakeLists.txt            |   65 +
+ tests/unit_test_giodbus/main.cpp                  |   12 +
+ tests/unit_test_giodbus/unit_test_giodbus.cpp     |   19 +
+ tests/unit_test_kalabel/CMakeLists.txt            |   59 +
+ tests/unit_test_kalabel/main.cpp                  |   67 +
+ tests/unit_test_keywatcher/CMakeLists.txt         |   60 +
+ tests/unit_test_keywatcher/main.cpp               |   50 +
+ tests/unit_test_loginoptionswidget/CMakeLists.txt |   77 +
+ tests/unit_test_loginoptionswidget/main.cpp       |  355 ++
+ tests/unit_test_modebutton/CMakeLists.txt         |   63 +
+ tests/unit_test_modebutton/main.cpp               |   94 +
+ tests/unit_test_pam_tally/CMakeLists.txt          |   59 +
+ tests/unit_test_pam_tally/main.cpp                |  113 +
+ tests/unit_test_personalizeddata/CMakeLists.txt   |   64 +
+ tests/unit_test_personalizeddata/main.cpp         |   92 +
+ tests/unit_test_rsac/CMakeLists.txt               |   61 +
+ tests/unit_test_rsac/main.cpp                     |  104 +
+ tests/unit_test_servicemanager/CMakeLists.txt     |   58 +
+ tests/unit_test_servicemanager/main.cpp           |   35 +
+ tests/unit_test_sessionmanager/CMakeLists.txt     |   59 +
+ tests/unit_test_sessionmanager/main.cpp           |   34 +
+ tests/unit_test_usdblockshortcut/CMakeLists.txt   |   59 +
+ tests/unit_test_usdblockshortcut/main.cpp         |   35 +
+ tests/unit_test_users/CMakeLists.txt              |   59 +
+ tests/unit_test_users/main.cpp                    |   86 +
+ uniauth-backend/src/main.cpp                      |    8 +-
+ uniauth-backend/src/personalizeddata.cpp          |    9 +
+ uniauth-backend/src/personalizeddata.h            |    6 +
+ uniauth-backend/src/serviceinterface.cpp          | 1056 +++--
+ uniauth-backend/src/serviceinterface.h            |  155 +-
+ 45 files changed, 9060 insertions(+), 516 deletions(-)
+ create mode 100644 tests/CMakeLists.txt
+ create mode 100644 tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp
+ create mode 100644 tests/kt-test-utils/cpp-stub-ext/stub-shadow.h
+ create mode 100644 tests/kt-test-utils/cpp-stub-ext/stubext.h
+ create mode 100644 tests/kt-test-utils/cpp-stub/addr_any.h
+ create mode 100644 tests/kt-test-utils/cpp-stub/addr_pri.h
+ create mode 100644 tests/kt-test-utils/cpp-stub/elfio.hpp
+ create mode 100644 tests/kt-test-utils/cpp-stub/stub.h
+ create mode 100644 tests/unit_test_biodeviceinfo/CMakeLists.txt
+ create mode 100644 tests/unit_test_biodeviceinfo/main.cpp
+ create mode 100644 tests/unit_test_biodevices/CMakeLists.txt
+ create mode 100644 tests/unit_test_biodevices/main.cpp
+ create mode 100644 tests/unit_test_common/CMakeLists.txt
+ create mode 100644 tests/unit_test_common/main.cpp
+ create mode 100644 tests/unit_test_common/unit_test_common.cpp
+ create mode 100644 tests/unit_test_giodbus/CMakeLists.txt
+ create mode 100644 tests/unit_test_giodbus/main.cpp
+ create mode 100644 tests/unit_test_giodbus/unit_test_giodbus.cpp
+ create mode 100644 tests/unit_test_kalabel/CMakeLists.txt
+ create mode 100644 tests/unit_test_kalabel/main.cpp
+ create mode 100644 tests/unit_test_keywatcher/CMakeLists.txt
+ create mode 100644 tests/unit_test_keywatcher/main.cpp
+ create mode 100644 tests/unit_test_loginoptionswidget/CMakeLists.txt
+ create mode 100644 tests/unit_test_loginoptionswidget/main.cpp
+ create mode 100644 tests/unit_test_modebutton/CMakeLists.txt
+ create mode 100644 tests/unit_test_modebutton/main.cpp
+ create mode 100644 tests/unit_test_pam_tally/CMakeLists.txt
+ create mode 100644 tests/unit_test_pam_tally/main.cpp
+ create mode 100644 tests/unit_test_personalizeddata/CMakeLists.txt
+ create mode 100644 tests/unit_test_personalizeddata/main.cpp
+ create mode 100644 tests/unit_test_rsac/CMakeLists.txt
+ create mode 100644 tests/unit_test_rsac/main.cpp
+ create mode 100644 tests/unit_test_servicemanager/CMakeLists.txt
+ create mode 100644 tests/unit_test_servicemanager/main.cpp
+ create mode 100644 tests/unit_test_sessionmanager/CMakeLists.txt
+ create mode 100644 tests/unit_test_sessionmanager/main.cpp
+ create mode 100644 tests/unit_test_usdblockshortcut/CMakeLists.txt
+ create mode 100644 tests/unit_test_usdblockshortcut/main.cpp
+ create mode 100644 tests/unit_test_users/CMakeLists.txt
+ create mode 100644 tests/unit_test_users/main.cpp
+
+diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
+new file mode 100644
+index 0000000..7b1af9b
+--- /dev/null
++++ b/tests/CMakeLists.txt
+@@ -0,0 +1,42 @@
++add_subdirectory(unit_test_giodbus)
++add_subdirectory(unit_test_biodeviceinfo)
++add_subdirectory(unit_test_kalabel)
++add_subdirectory(unit_test_rsac)
++add_subdirectory(unit_test_pam_tally)
++add_subdirectory(unit_test_common)
++add_subdirectory(unit_test_loginoptionswidget)
++add_subdirectory(unit_test_keywatcher)
++add_subdirectory(unit_test_personalizeddata)
++add_subdirectory(unit_test_modebutton)
++add_subdirectory(unit_test_users)
++add_subdirectory(unit_test_biodevices)
++add_subdirectory(unit_test_usdblockshortcut)
++add_subdirectory(unit_test_sessionmanager)
++add_subdirectory(unit_test_servicemanager)
++
++# 处理打桩工具相关配置
++set(TEST_UTILS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/kt-test-utils")
++
++# 收集打桩工具的头文件,递归查找符合条件的头文件
++file(GLOB_RECURSE UTILS_HEADERS
++    "${TEST_UTILS_PATH}/cpp-stub/*.h"
++    "${TEST_UTILS_PATH}/cpp-stub/*.hpp"
++    "${TEST_UTILS_PATH}/cpp-stub-ext/*.h"
++)
++
++# 收集打桩工具的源文件,递归查找符合条件的源文件
++file(GLOB_RECURSE UTILS_SOURCES
++    "${TEST_UTILS_PATH}/cpp-stub/*.cpp"
++    "${TEST_UTILS_PATH}/cpp-stub-ext/*.cpp"
++)
++
++# 创建一个库(这里以静态库为例,可以根据需求改为共享库等)来存放打桩工具相关代码
++add_library(utils_lib STATIC ${UTILS_SOURCES} ${UTILS_HEADERS})
++
++# 将打桩工具库的头文件目录添加到包含路径,方便其他目标使用
++target_include_directories(utils_lib
++    PUBLIC
++        "${TEST_UTILS_PATH}/cpp-stub"
++        "${TEST_UTILS_PATH}/cpp-stub-ext"
++)
++
+diff --git a/tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp b/tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp
+new file mode 100644
+index 0000000..ff21dcd
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp
+@@ -0,0 +1,58 @@
++/*
++ * Author:     Zhang Yu <clauszy@163.com>
++ * Maintainer: Zhang Yu <clauszy@163.com>
++ *
++ * MIT License
++ *
++ * Copyright (c) 2020 Zhang Yu
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in all
++ * copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++*/
++#include "stub-shadow.h"
++
++namespace stub_ext {
++
++WrapperMap stub_wrappers;
++
++Wrapper::Wrapper()
++{
++
++}
++
++Wrapper::~Wrapper()
++{
++
++}
++
++void freeWrapper(Wrapper *wrapper)
++{
++    if (!wrapper)
++        return;
++
++    for (auto iter = stub_wrappers.begin(); iter != stub_wrappers.end();) {
++        if (iter->second == wrapper)
++            iter = stub_wrappers.erase(iter);
++        else
++            ++iter;
++    }
++
++    delete wrapper;
++}
++}
++
+diff --git a/tests/kt-test-utils/cpp-stub-ext/stub-shadow.h b/tests/kt-test-utils/cpp-stub-ext/stub-shadow.h
+new file mode 100644
+index 0000000..04e746e
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub-ext/stub-shadow.h
+@@ -0,0 +1,171 @@
++
++#ifndef STUBSHADOW_H
++#define STUBSHADOW_H
++/*
++ * Author:     Zhang Yu <clauszy@163.com>
++ * Maintainer: Zhang Yu <clauszy@163.com>
++ *
++ * MIT License
++ *
++ * Copyright (c) 2020 Zhang Yu
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in all
++ * copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++*/
++#include <unordered_map>
++#include <assert.h>
++
++namespace stub_ext {
++
++#define LAMDA_FUNCTION_TYPE decltype(&Lamda::operator())
++
++class Wrapper
++{
++public:
++    Wrapper();
++    virtual ~Wrapper();
++};
++
++typedef std::unordered_map<long, Wrapper* > WrapperMap;
++extern WrapperMap stub_wrappers;
++
++template<class Lamda>
++class LamdaWrapper : public Wrapper
++{
++public:
++    LamdaWrapper(Lamda func): Wrapper(),_func(func){}
++    ~LamdaWrapper(){}
++    Lamda _func;
++};
++
++template <typename Func>
++struct VFLocator
++{
++
++};
++
++template <class Obj, typename Ret, typename... Args>
++struct VFLocator<Ret (Obj::*)(Args...)>
++{
++    typedef Ret (*Func)(Obj*, Args...);
++};
++
++template <class Obj, typename Ret, typename... Args>
++struct VFLocator<Ret (Obj::*)(Args...) const>
++{
++    typedef Ret (*Func)(Obj*, Args...);
++};
++
++template <typename Func>
++struct LamdaCaller
++{
++
++};
++
++template <class Obj, typename Ret, typename... Args>
++struct LamdaCaller<Ret (Obj::*)(Args...) const>
++{
++    template<class Lamda, typename ...OrgArgs>
++    static Ret call(LamdaWrapper<Lamda> *wrapper, OrgArgs&&... args)
++    {
++        return wrapper->_func(std::forward<OrgArgs>(args)...);
++    }
++};
++
++template <class Obj, typename Ret>
++struct LamdaCaller<Ret (Obj::*)() const>
++{
++    template<class Lamda, typename ...OrgArgs>
++    static Ret call(LamdaWrapper<Lamda> *wrapper, OrgArgs&&... args)
++    {
++        return wrapper->_func();
++    }
++};
++
++template<typename Func, class Lamda>
++struct FuncShadow
++{
++
++};
++
++template<typename Ret, typename... Args, class Lamda>
++struct FuncShadow<Ret (*)(Args...), Lamda>
++{
++    typedef Ret (*Shadow)(Args...);
++    typedef Ret RetType;
++
++    static Ret call(Args ...args)
++    {
++       Shadow shadow = &call;
++       long id = (long)shadow;
++       auto iter = stub_wrappers.find(id);
++       assert(stub_wrappers.find(id) != stub_wrappers.end());
++       LamdaWrapper<Lamda> *wrapper = dynamic_cast<LamdaWrapper<Lamda> *>(iter->second);
++       return LamdaCaller<LAMDA_FUNCTION_TYPE>::call(wrapper, args...);
++    }
++};
++
++template<typename Ret, class Obj,typename... Args, class Lamda>
++struct FuncShadow<Ret (Obj::*)(Args...), Lamda>
++{
++    typedef Ret (*Shadow)(Obj *,Args...);
++    typedef Ret RetType;
++    static Ret call(Obj *obj, Args ...args)
++    {
++        Shadow shadow = &call;
++        long id = (long)shadow;
++        auto iter = stub_wrappers.find(id);
++        assert(stub_wrappers.find(id) != stub_wrappers.end());
++        LamdaWrapper<Lamda> *wrapper = dynamic_cast<LamdaWrapper<Lamda> *>(iter->second);
++        return LamdaCaller<LAMDA_FUNCTION_TYPE>::call(wrapper, obj, args...);
++    }
++};
++
++
++template<typename Ret, class Obj,typename... Args, class Lamda>
++struct FuncShadow<Ret (Obj::*)(Args...) const, Lamda>
++{
++    typedef Ret (*Shadow)(Obj *,Args...);
++    typedef Ret RetType;
++    static Ret call(Obj *obj, Args ...args)
++    {
++        Shadow shadow = &call;
++        long id = (long)shadow;
++        auto iter = stub_wrappers.find(id);
++        assert(stub_wrappers.find(id) != stub_wrappers.end());
++        LamdaWrapper<Lamda> *wrapper = dynamic_cast<LamdaWrapper<Lamda> *>(iter->second);
++        return LamdaCaller<LAMDA_FUNCTION_TYPE>::call(wrapper, obj, args...);
++    }
++};
++
++template<typename Func, class Lamda>
++typename FuncShadow<Func, Lamda>::Shadow depictShadow(Wrapper **wrapper, Func func, Lamda lamda)
++{
++    *wrapper = new LamdaWrapper<Lamda>(lamda);
++    typename FuncShadow<Func,Lamda>::Shadow shadow = &FuncShadow<Func,Lamda>::call;
++    long id = (long)shadow;
++    assert(stub_wrappers.find(id) == stub_wrappers.end());
++    stub_wrappers.insert(std::make_pair(id,*wrapper));
++    return shadow;
++}
++
++void freeWrapper(Wrapper *wrapper);
++
++}
++
++#endif // STUBSHADOW_H
+diff --git a/tests/kt-test-utils/cpp-stub-ext/stubext.h b/tests/kt-test-utils/cpp-stub-ext/stubext.h
+new file mode 100644
+index 0000000..2a70a78
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub-ext/stubext.h
+@@ -0,0 +1,129 @@
++
++#ifndef STUBEXT_H
++#define STUBEXT_H
++/*
++ * Author:     Zhang Yu <clauszy@163.com>
++ * Maintainer: Zhang Yu <clauszy@163.com>
++ *
++ * MIT License
++ *
++ * Copyright (c) 2020 Zhang Yu
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in all
++ * copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++*/
++//需修改Stub的私用成员函数和成员变量为保护类型
++#include "stub.h"
++
++#include "stub-shadow.h"
++
++#ifdef DEBUG_STUB_INVOKE
++// use to make sure the stub function is invoked.
++#    define __DBG_STUB_INVOKE__ printf("stub at %s:%d is invoked.\n", __FILE__, __LINE__);
++#else
++#    define __DBG_STUB_INVOKE__
++#endif
++
++#define VADDR(CLASS_NAME, MEMBER_NAME) (typename stub_ext::VFLocator<decltype(&CLASS_NAME::MEMBER_NAME)>::Func)(&CLASS_NAME::MEMBER_NAME)
++
++namespace stub_ext {
++
++class StubExt : public Stub
++{
++public:
++    StubExt()
++        : Stub() { }
++
++    template<typename T, class Lamda>
++    bool set_lamda(T addr, Lamda lamda)
++    {
++        char *fn = addrof(addr);
++        if (m_result.find(fn) != m_result.end())
++            reset(addr);
++
++        Wrapper *wrapper = nullptr;
++        auto addr_stub = depictShadow(&wrapper, addr, lamda);
++        if (set(addr, addr_stub)) {
++            m_wrappers.insert(std::make_pair(fn, wrapper));
++            return true;
++        } else {
++            freeWrapper(wrapper);
++        }
++        return false;
++    }
++
++    template<typename T>
++    void reset(T addr)
++    {
++        Stub::reset(addr);
++        char *fn = addrof(addr);
++        auto iter = m_wrappers.find(fn);
++        if (iter != m_wrappers.end()) {
++            freeWrapper(iter->second);
++            m_wrappers.erase(iter);
++        }
++    }
++
++    ~StubExt()
++    {
++        clear();
++    }
++
++    void clear() override
++    {
++        Stub::clear();
++        for (auto iter = m_wrappers.begin(); iter != m_wrappers.end(); ++iter) {
++            freeWrapper(iter->second);
++        }
++        m_wrappers.clear();
++    }
++
++    template<class T>
++    static void *get_ctor_addr(bool start = true)
++    {
++        // the start vairable must be true, or the compiler will optimize out.
++        if (start) goto Start;
++    Call_Constructor:
++        // This line of code will not be executed.
++        // The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor.
++        T();
++    Start:
++        // The address of the line of code T() obtained by assembly
++        char *p = (char *)&&Call_Constructor;   // https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
++        // CALL rel32
++        void *ret = 0;
++        char pos;
++        char call = 0xe8;
++        do {
++            pos = *p;
++            if (pos == call) {
++                ret = p + 5 + (*(int *)(p + 1));
++            }
++
++        } while (!ret && (++p));
++
++        return ret;
++    }
++
++protected:
++    std::map<char *, Wrapper *> m_wrappers;
++};
++
++}
++
++#endif   // STUBEXT_H
+diff --git a/tests/kt-test-utils/cpp-stub/addr_any.h b/tests/kt-test-utils/cpp-stub/addr_any.h
+new file mode 100644
+index 0000000..a153f34
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub/addr_any.h
+@@ -0,0 +1,280 @@
++#ifndef __ADDR_ANY_H__
++#define __ADDR_ANY_H__
++
++
++//linux
++#include <regex.h>
++#include <cxxabi.h>
++//c
++#include <cinttypes>
++#include <cstdio>
++#include <cstdlib>
++
++//c++
++#include <string>
++#include <map>
++//project
++#include "elfio.hpp"
++
++
++
++class AddrAny
++{
++public:
++    AddrAny()
++    {
++        m_init = get_exe_pathname(m_fullname);
++        m_baseaddr = 0;
++    }
++    AddrAny(std::string libname)
++    {
++        m_init = get_lib_pathname_and_baseaddr(libname, m_fullname, m_baseaddr);
++    }
++
++    int get_local_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        return get_func_addr(SHT_SYMTAB, STB_LOCAL, func_name_regex_str, result);
++    }
++    int get_global_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        return get_func_addr(SHT_SYMTAB, STB_GLOBAL, func_name_regex_str, result);
++    }
++    int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        return get_func_addr(SHT_SYMTAB, STB_WEAK, func_name_regex_str, result);
++    }
++    
++    int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        return get_func_addr(SHT_DYNSYM, STB_GLOBAL, func_name_regex_str, result);
++    }
++    int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        return get_func_addr(SHT_DYNSYM, STB_WEAK, func_name_regex_str, result);
++    }
++    
++private:
++    bool demangle(std::string& s, std::string& name) {
++        int status;
++        char* pname = abi::__cxa_demangle(s.c_str(), 0, 0, &status);
++        if (status != 0)
++        {
++            switch(status)
++            {
++                case -1: name = "memory allocation error"; break;
++                case -2: name = "invalid name given"; break;
++                case -3: name = "internal error: __cxa_demangle: invalid argument"; break;
++                default: name = "unknown error occured"; break;
++            }
++            return false;
++        }
++        name = pname;
++        free(pname);
++        return true;
++    }
++    bool get_exe_pathname( std::string& name)
++    {
++        char                     line[512];
++        FILE                    *fp;
++        uintptr_t                base_addr;
++        char                     perm[5];
++        unsigned long            offset;
++        int                      pathname_pos;
++        char                    *pathname;
++        size_t                   pathname_len;
++        int                      match = 0;
++        
++        if(NULL == (fp = fopen("/proc/self/maps", "r")))
++        {
++            return false;
++        }
++
++        while(fgets(line, sizeof(line), fp))
++        {
++            if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
++
++            if(0 != offset) continue;
++
++            //get pathname
++            while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
++                pathname_pos += 1;
++            if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
++            pathname = line + pathname_pos;
++            pathname_len = strlen(pathname);
++            if(0 == pathname_len) continue;
++            if(pathname[pathname_len - 1] == '\n')
++            {
++                pathname[pathname_len - 1] = '\0';
++                pathname_len -= 1;
++            }
++            if(0 == pathname_len) continue;
++            if('[' == pathname[0]) continue;
++
++            name = pathname;
++            match = 1;
++            break;
++
++        }
++        fclose(fp);
++
++        if(0 == match)
++        {
++            return false;
++        }
++        else
++        {
++            return true;
++        }
++
++    }
++
++    bool get_lib_pathname_and_baseaddr(std::string pathname_regex_str, std::string& name, unsigned long& addr)
++    {
++        char                     line[512];
++        FILE                    *fp;
++        uintptr_t                base_addr;
++        char                     perm[5];
++        unsigned long            offset;
++        int                      pathname_pos;
++        char                    *pathname;
++        size_t                   pathname_len;
++        int                      match;
++        regex_t   pathname_regex;
++
++        regcomp(&pathname_regex, pathname_regex_str.c_str(), 0);
++
++        if(NULL == (fp = fopen("/proc/self/maps", "r")))
++        {
++            return false;
++        }
++
++        while(fgets(line, sizeof(line), fp))
++        {
++            if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
++
++            //check permission
++            if(perm[0] != 'r') continue;
++            if(perm[3] != 'p') continue; //do not touch the shared memory
++
++            //check offset
++            //
++            //We are trying to find ELF header in memory.
++            //It can only be found at the beginning of a mapped memory regions
++            //whose offset is 0.
++            if(0 != offset) continue;
++
++            //get pathname
++            while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
++                pathname_pos += 1;
++            if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
++            pathname = line + pathname_pos;
++            pathname_len = strlen(pathname);
++            if(0 == pathname_len) continue;
++            if(pathname[pathname_len - 1] == '\n')
++            {
++                pathname[pathname_len - 1] = '\0';
++                pathname_len -= 1;
++            }
++            if(0 == pathname_len) continue;
++            if('[' == pathname[0]) continue;
++
++            //check pathname
++            //if we need to hook this elf?
++            match = 0;
++            if(0 == regexec(&pathname_regex, pathname, 0, NULL, 0))
++            {
++                match = 1;
++                name = pathname;
++                addr = (unsigned long)base_addr;
++                break;
++            }
++            if(0 == match) continue;
++
++        }
++        fclose(fp);
++        if(0 == match)
++        {
++            return false;
++        }
++        else
++        {
++            return true;
++        }
++
++    }
++
++    int get_func_addr(unsigned int ttype, unsigned int stype, std::string& func_name_regex_str, std::map<std::string,void*>& result)
++    {
++        // Create an elfio reader
++        ELFIO::elfio reader;
++        int count = 0;
++        regex_t   pathname_regex;
++
++        if(!m_init)
++        {
++            return -1;
++        }
++
++        regcomp(&pathname_regex, func_name_regex_str.c_str(), 0);
++        // Load ELF data
++        if(!reader.load(m_fullname.c_str()))
++        {
++            return -1;
++        }
++        
++        ELFIO::Elf_Half sec_num = reader.sections.size();
++        for(int i = 0; i < sec_num; ++i)
++        {
++            ELFIO::section* psec = reader.sections[i];
++            // Check section type
++            if(psec->get_type() == ttype)
++            {
++                const ELFIO::symbol_section_accessor symbols( reader, psec );
++                for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j )
++                {
++                    std::string name;
++                    std::string name_mangle;
++                    ELFIO::Elf64_Addr value;
++                    ELFIO::Elf_Xword size;
++                    unsigned char bind;
++                    unsigned char type;
++                    ELFIO::Elf_Half section_index;
++                    unsigned char other;
++                    
++                    // Read symbol properties
++                    symbols.get_symbol( j, name, value, size, bind, type, section_index, other );
++                    if(type == STT_FUNC && bind == stype)
++                    {
++                        bool ret = demangle(name,name_mangle);
++                        if(ret == true)
++                        {
++                            if (0 == regexec(&pathname_regex, name_mangle.c_str(), 0, NULL, 0))
++                            {
++                                  result.insert ( std::pair<std::string,void *>(name_mangle,(void*)(value + m_baseaddr)));
++                                  count++;
++                            }
++                        }
++                        else
++                        {
++                            if (0 == regexec(&pathname_regex, name.c_str(), 0, NULL, 0))
++                            {
++                                  result.insert ( std::pair<std::string,void *>(name,(void*)(value + m_baseaddr)));
++                                  count++;
++                            }
++                        }
++                    }
++                }
++                break;
++            }
++        }
++        
++        return count;
++    }
++private:
++    bool m_init;
++    std::string m_name;
++    std::string m_fullname;
++    unsigned long m_baseaddr;
++
++};
++#endif
+diff --git a/tests/kt-test-utils/cpp-stub/addr_pri.h b/tests/kt-test-utils/cpp-stub/addr_pri.h
+new file mode 100644
+index 0000000..9174bb0
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub/addr_pri.h
+@@ -0,0 +1,177 @@
++#ifndef __ADDR_PRI_H__
++#define __ADDR_PRI_H__
++
++
++#include <utility>
++#include <type_traits>
++
++
++
++//base on C++11
++
++/**********************************************************
++             access private function
++**********************************************************/
++
++
++namespace std {
++  template <bool B, class T = void>
++  using enable_if_t = typename enable_if<B, T>::type;
++  template <class T>
++  using remove_reference_t = typename remove_reference<T>::type;
++} // std
++
++// Unnamed namespace is used to avoid duplicate symbols if the macros are used
++namespace {
++  namespace private_access_detail {
++
++    // @tparam TagType, used to declare different "get" funciton overloads for
++    // different members/statics
++    template <typename PtrType, PtrType PtrValue, typename TagType>
++    struct private_access {
++      // Normal lookup cannot find in-class defined (inline) friend functions.
++      friend PtrType get(TagType) { return PtrValue; }
++    };
++
++  } // namespace private_access_detail
++} // namespace
++
++// Used macro naming conventions:
++// The "namespace" of this macro library is PRIVATE_ACCESS, i.e. all
++// macro here has this prefix.
++// All implementation macro, which are not meant to be used directly have the
++// PRIVATE_ACCESS_DETAIL prefix.
++// Some macros have the ABCD_IMPL form, which means they contain the
++// implementation details for the specific ABCD macro.
++
++#define PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) x##y
++#define PRIVATE_ACCESS_DETAIL_CONCATENATE(x, y)                                \
++  PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y)
++
++// @param PtrTypeKind E.g if we have "class A", then it can be "A::*" in case of
++// members, or it can be "*" in case of statics.
++#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name,           \
++                                             PtrTypeKind)                      \
++  namespace {                                                                  \
++    namespace private_access_detail {                                          \
++      /* Tag type, used to declare different get funcitons for different       \
++       * members                                                               \
++       */                                                                      \
++      struct Tag {};                                                           \
++      /* Explicit instantiation */                                             \
++      template struct private_access<decltype(&Class::Name), &Class::Name,     \
++                                     Tag>;                                     \
++      /* We can build the PtrType only with two aliases */                     \
++      /* E.g. using PtrType = int(int) *; would be illformed */                \
++      using PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) = Type;             \
++      using PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) =                 \
++          PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) PtrTypeKind;          \
++      /* Declare the friend function, now it is visible in namespace scope.    \
++       * Note,                                                                 \
++       * we could declare it inside the Tag type too, in that case ADL would   \
++       * find                                                                  \
++       * the declaration. By choosing to declare it here, the Tag type remains \
++       * a                                                                     \
++       * simple tag type, it has no other responsibilities. */                 \
++      PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) get(Tag);               \
++    }                                                                          \
++  }
++
++#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(Tag, Class, Type, Name)     \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*)       \
++  namespace {                                                                  \
++    namespace access_private_field {                                                  \
++      Type &Class##Name(Class &&t) { return t.*get(private_access_detail::Tag{}); }   \
++      Type &Class##Name(Class &t) { return t.*get(private_access_detail::Tag{}); }    \
++      /* The following usings are here to avoid duplicate const qualifier      \
++       * warnings                                                              \
++       */                                                                      \
++      using PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag) = Type;                  \
++      using PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) =                        \
++          const PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag);                     \
++      PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) & Class##Name(const Class &t) {\
++        return t.*get(private_access_detail::Tag{});                           \
++      }                                                                        \
++    }                                                                          \
++  }
++
++#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(Tag, Class, Type, Name)       \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*)       \
++  namespace {                                                                  \
++    namespace call_private_fun {                                               \
++      /* We do perfect forwarding, but we want to restrict the overload set    \
++       * only for objects which have the type Class. */                        \
++      template <typename Obj,                                                  \
++                std::enable_if_t<std::is_same<std::remove_reference_t<Obj>,    \
++                                              Class>::value> * = nullptr,      \
++                typename... Args>                                              \
++      auto Class##Name(Obj &&o, Args &&... args) -> decltype(                  \
++          (std::forward<Obj>(o).*                                              \
++           get(private_access_detail::Tag{}))(std::forward<Args>(args)...)) {  \
++        return (std::forward<Obj>(o).*get(private_access_detail::Tag{}))(      \
++            std::forward<Args>(args)...);                                      \
++      }                                                                        \
++    }                                                                          \
++    namespace get_private_fun {                                                \
++      auto Class##Name()  -> decltype(                                         \
++          get(private_access_detail::Tag{})) {                                 \
++        return (get(private_access_detail::Tag{}));                            \
++      }                                                                        \
++    }                                                                          \
++  }
++
++#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD(Tag, Class, Type,    \
++                                                          Name)                \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *)              \
++  namespace {                                                                  \
++    namespace access_private_static_field {                                    \
++      namespace Class {                                                        \
++        Type &Class##Name() { return *get(private_access_detail::Tag{}); }     \
++      }                                                                        \
++    }                                                                          \
++  }
++
++#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN(Tag, Class, Type,      \
++                                                        Name)                  \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *)              \
++  namespace {                                                                  \
++    namespace call_private_static_fun {                                        \
++      namespace Class {                                                        \
++        template <typename... Args>                                            \
++        auto Class##Name(Args &&... args) -> decltype(                         \
++            get(private_access_detail::Tag{})(std::forward<Args>(args)...)) {  \
++          return get(private_access_detail::Tag{})(                            \
++              std::forward<Args>(args)...);                                    \
++        }                                                                      \
++      }                                                                        \
++    }                                                                          \
++    namespace get_private_static_fun {                                         \
++      namespace Class {                                                        \
++        auto Class##Name() -> decltype(get(private_access_detail::Tag{})) {    \
++          return get(private_access_detail::Tag{});                            \
++        }                                                                      \
++      }                                                                        \
++    }                                                                          \
++  }
++
++#define PRIVATE_ACCESS_DETAIL_UNIQUE_TAG                                       \
++  PRIVATE_ACCESS_DETAIL_CONCATENATE(PrivateAccessTag, __COUNTER__)
++
++#define ACCESS_PRIVATE_FIELD(Class, Type, Name)                                \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \
++                                             Class, Type, Name)
++
++#define ACCESS_PRIVATE_FUN(Class, Type, Name)                                  \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG,   \
++                                           Class, Type, Name)
++
++#define ACCESS_PRIVATE_STATIC_FIELD(Class, Type, Name)                         \
++    Type Class::Name;                                                          \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD(                           \
++      PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name)
++
++#define ACCESS_PRIVATE_STATIC_FUN(Class, Type, Name)                           \
++  PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN(                             \
++      PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name)
++
++#endif
+diff --git a/tests/kt-test-utils/cpp-stub/elfio.hpp b/tests/kt-test-utils/cpp-stub/elfio.hpp
+new file mode 100644
+index 0000000..dd5c9ae
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub/elfio.hpp
+@@ -0,0 +1,4888 @@
++
++/*** Start of inlined file: elfio_dump.hpp ***/
++#ifndef ELFIO_DUMP_HPP
++#define ELFIO_DUMP_HPP
++
++#include <algorithm>
++#include <string>
++#include <ostream>
++#include <sstream>
++#include <iomanip>
++
++/*** Start of inlined file: elfio.hpp ***/
++#ifndef ELFIO_HPP
++#define ELFIO_HPP
++
++#ifdef _MSC_VER
++#pragma warning( push )
++#pragma warning( disable : 4996 )
++#pragma warning( disable : 4355 )
++#pragma warning( disable : 4244 )
++#endif
++
++#include <string>
++#include <iostream>
++#include <fstream>
++#include <functional>
++#include <algorithm>
++#include <vector>
++#include <deque>
++#include <iterator>
++
++
++/*** Start of inlined file: elf_types.hpp ***/
++#ifndef ELFTYPES_H
++#define ELFTYPES_H
++
++#ifndef ELFIO_NO_OWN_TYPES
++#if !defined( ELFIO_NO_CSTDINT ) && !defined( ELFIO_NO_INTTYPES )
++#include <stdint.h>
++#else
++typedef unsigned char    uint8_t;
++typedef signed char      int8_t;
++typedef unsigned short   uint16_t;
++typedef signed short     int16_t;
++#ifdef _MSC_VER
++typedef unsigned __int32 uint32_t;
++typedef signed __int32   int32_t;
++typedef unsigned __int64 uint64_t;
++typedef signed __int64   int64_t;
++#else
++typedef unsigned int       uint32_t;
++typedef signed int         int32_t;
++typedef unsigned long long uint64_t;
++typedef signed long long   int64_t;
++#endif // _MSC_VER
++#endif // ELFIO_NO_CSTDINT
++#endif // ELFIO_NO_OWN_TYPES
++
++namespace ELFIO {
++
++// Attention! Platform depended definitions.
++typedef uint16_t Elf_Half;
++typedef uint32_t Elf_Word;
++typedef int32_t  Elf_Sword;
++typedef uint64_t Elf_Xword;
++typedef int64_t  Elf_Sxword;
++
++typedef uint32_t Elf32_Addr;
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Addr;
++typedef uint64_t Elf64_Off;
++
++#define Elf32_Half  Elf_Half
++#define Elf64_Half  Elf_Half
++#define Elf32_Word  Elf_Word
++#define Elf64_Word  Elf_Word
++#define Elf32_Sword Elf_Sword
++#define Elf64_Sword Elf_Sword
++
++///////////////////////
++// ELF Header Constants
++
++// File type
++#define ET_NONE   0
++#define ET_REL    1
++#define ET_EXEC   2
++#define ET_DYN    3
++#define ET_CORE   4
++#define ET_LOOS   0xFE00
++#define ET_HIOS   0xFEFF
++#define ET_LOPROC 0xFF00
++#define ET_HIPROC 0xFFFF
++
++#define EM_NONE  0 // No machine
++#define EM_M32   1 // AT&T WE 32100
++#define EM_SPARC 2 // SUN SPARC
++#define EM_386   3 // Intel 80386
++#define EM_68K   4 // Motorola m68k family
++#define EM_88K   5 // Motorola m88k family
++#define EM_486   6 // Intel 80486// Reserved for future use
++#define EM_860   7 // Intel 80860
++#define EM_MIPS  8 // MIPS R3000 (officially, big-endian only)
++#define EM_S370  9 // IBM System/370
++#define EM_MIPS_RS3_LE \
++	10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated
++#define EM_res011      11 // Reserved
++#define EM_res012      12 // Reserved
++#define EM_res013      13 // Reserved
++#define EM_res014      14 // Reserved
++#define EM_PARISC      15 // HPPA
++#define EM_res016      16 // Reserved
++#define EM_VPP550      17 // Fujitsu VPP500
++#define EM_SPARC32PLUS 18 // Sun's "v8plus"
++#define EM_960         19 // Intel 80960
++#define EM_PPC         20 // PowerPC
++#define EM_PPC64       21 // 64-bit PowerPC
++#define EM_S390        22 // IBM S/390
++#define EM_SPU         23 // Sony/Toshiba/IBM SPU
++#define EM_res024      24 // Reserved
++#define EM_res025      25 // Reserved
++#define EM_res026      26 // Reserved
++#define EM_res027      27 // Reserved
++#define EM_res028      28 // Reserved
++#define EM_res029      29 // Reserved
++#define EM_res030      30 // Reserved
++#define EM_res031      31 // Reserved
++#define EM_res032      32 // Reserved
++#define EM_res033      33 // Reserved
++#define EM_res034      34 // Reserved
++#define EM_res035      35 // Reserved
++#define EM_V800        36 // NEC V800 series
++#define EM_FR20        37 // Fujitsu FR20
++#define EM_RH32        38 // TRW RH32
++#define EM_MCORE       39 // Motorola M*Core // May also be taken by Fujitsu MMA
++#define EM_RCE         39 // Old name for MCore
++#define EM_ARM         40 // ARM
++#define EM_OLD_ALPHA   41 // Digital Alpha
++#define EM_SH          42 // Renesas (formerly Hitachi) / SuperH SH
++#define EM_SPARCV9     43 // SPARC v9 64-bit
++#define EM_TRICORE     44 // Siemens Tricore embedded processor
++#define EM_ARC         45 // ARC Cores
++#define EM_H8_300      46 // Renesas (formerly Hitachi) H8/300
++#define EM_H8_300H     47 // Renesas (formerly Hitachi) H8/300H
++#define EM_H8S         48 // Renesas (formerly Hitachi) H8S
++#define EM_H8_500      49 // Renesas (formerly Hitachi) H8/500
++#define EM_IA_64       50 // Intel IA-64 Processor
++#define EM_MIPS_X      51 // Stanford MIPS-X
++#define EM_COLDFIRE    52 // Motorola Coldfire
++#define EM_68HC12      53 // Motorola M68HC12
++#define EM_MMA         54 // Fujitsu Multimedia Accelerator
++#define EM_PCP         55 // Siemens PCP
++#define EM_NCPU        56 // Sony nCPU embedded RISC processor
++#define EM_NDR1        57 // Denso NDR1 microprocesspr
++#define EM_STARCORE    58 // Motorola Star*Core processor
++#define EM_ME16        59 // Toyota ME16 processor
++#define EM_ST100       60 // STMicroelectronics ST100 processor
++#define EM_TINYJ       61 // Advanced Logic Corp. TinyJ embedded processor
++#define EM_X86_64      62 // Advanced Micro Devices X86-64 processor
++#define EM_PDSP        63 // Sony DSP Processor
++#define EM_PDP10       64 // Digital Equipment Corp. PDP-10
++#define EM_PDP11       65 // Digital Equipment Corp. PDP-11
++#define EM_FX66        66 // Siemens FX66 microcontroller
++#define EM_ST9PLUS     67 // STMicroelectronics ST9+ 8/16 bit microcontroller
++#define EM_ST7         68 // STMicroelectronics ST7 8-bit microcontroller
++#define EM_68HC16      69 // Motorola MC68HC16 Microcontroller
++#define EM_68HC11      70 // Motorola MC68HC11 Microcontroller
++#define EM_68HC08      71 // Motorola MC68HC08 Microcontroller
++#define EM_68HC05      72 // Motorola MC68HC05 Microcontroller
++#define EM_SVX         73 // Silicon Graphics SVx
++#define EM_ST19        74 // STMicroelectronics ST19 8-bit cpu
++#define EM_VAX         75 // Digital VAX
++#define EM_CRIS        76 // Axis Communications 32-bit embedded processor
++#define EM_JAVELIN     77 // Infineon Technologies 32-bit embedded cpu
++#define EM_FIREPATH    78 // Element 14 64-bit DSP processor
++#define EM_ZSP         79 // LSI Logic's 16-bit DSP processor
++#define EM_MMIX        80 // Donald Knuth's educational 64-bit processor
++#define EM_HUANY       81 // Harvard's machine-independent format
++#define EM_PRISM       82 // SiTera Prism
++#define EM_AVR         83 // Atmel AVR 8-bit microcontroller
++#define EM_FR30        84 // Fujitsu FR30
++#define EM_D10V        85 // Mitsubishi D10V
++#define EM_D30V        86 // Mitsubishi D30V
++#define EM_V850        87 // NEC v850
++#define EM_M32R        88 // Renesas M32R (formerly Mitsubishi M32R)
++#define EM_MN10300     89 // Matsushita MN10300
++#define EM_MN10200     90 // Matsushita MN10200
++#define EM_PJ          91 // picoJava
++#define EM_OPENRISC    92 // OpenRISC 32-bit embedded processor
++#define EM_ARC_A5      93 // ARC Cores Tangent-A5
++#define EM_XTENSA      94 // Tensilica Xtensa Architecture
++#define EM_VIDEOCORE   95 // Alphamosaic VideoCore processor
++#define EM_TMM_GPP     96 // Thompson Multimedia General Purpose Processor
++#define EM_NS32K       97 // National Semiconductor 32000 series
++#define EM_TPC         98 // Tenor Network TPC processor
++#define EM_SNP1K       99 // Trebia SNP 1000 processor
++#define EM_ST200       100 // STMicroelectronics ST200 microcontroller
++#define EM_IP2K        101 // Ubicom IP2022 micro controller
++#define EM_MAX         102 // MAX Processor
++#define EM_CR          103 // National Semiconductor CompactRISC
++#define EM_F2MC16      104 // Fujitsu F2MC16
++#define EM_MSP430      105 // TI msp430 micro controller
++#define EM_BLACKFIN    106 // ADI Blackfin
++#define EM_SE_C33      107 // S1C33 Family of Seiko Epson processors
++#define EM_SEP         108 // Sharp embedded microprocessor
++#define EM_ARCA        109 // Arca RISC Microprocessor
++#define EM_UNICORE \
++	110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University
++#define EM_EXCESS       111 // eXcess: 16/32/64-bit configurable embedded CPU
++#define EM_DXP          112 // Icera Semiconductor Inc. Deep Execution Processor
++#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor
++#define EM_CRX          114 // National Semiconductor CRX
++#define EM_XGATE        115 // Motorola XGATE embedded processor
++#define EM_C166         116 // Infineon C16x/XC16x processor
++#define EM_M16C         117 // Renesas M16C series microprocessors
++#define EM_DSPIC30F \
++	118 // Microchip Technology dsPIC30F Digital Signal Controller
++#define EM_CE            119 // Freescale Communication Engine RISC core
++#define EM_M32C          120 // Renesas M32C series microprocessors
++#define EM_res121        121 // Reserved
++#define EM_res122        122 // Reserved
++#define EM_res123        123 // Reserved
++#define EM_res124        124 // Reserved
++#define EM_res125        125 // Reserved
++#define EM_res126        126 // Reserved
++#define EM_res127        127 // Reserved
++#define EM_res128        128 // Reserved
++#define EM_res129        129 // Reserved
++#define EM_res130        130 // Reserved
++#define EM_TSK3000       131 // Altium TSK3000 core
++#define EM_RS08          132 // Freescale RS08 embedded processor
++#define EM_res133        133 // Reserved
++#define EM_ECOG2         134 // Cyan Technology eCOG2 microprocessor
++#define EM_SCORE         135 // Sunplus Score
++#define EM_SCORE7        135 // Sunplus S+core7 RISC processor
++#define EM_DSP24         136 // New Japan Radio (NJR) 24-bit DSP Processor
++#define EM_VIDEOCORE3    137 // Broadcom VideoCore III processor
++#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture
++#define EM_SE_C17        139 // Seiko Epson C17 family
++#define EM_TI_C6000      140 // Texas Instruments TMS320C6000 DSP family
++#define EM_TI_C2000      141 // Texas Instruments TMS320C2000 DSP family
++#define EM_TI_C5500      142 // Texas Instruments TMS320C55x DSP family
++#define EM_res143        143 // Reserved
++#define EM_res144        144 // Reserved
++#define EM_res145        145 // Reserved
++#define EM_res146        146 // Reserved
++#define EM_res147        147 // Reserved
++#define EM_res148        148 // Reserved
++#define EM_res149        149 // Reserved
++#define EM_res150        150 // Reserved
++#define EM_res151        151 // Reserved
++#define EM_res152        152 // Reserved
++#define EM_res153        153 // Reserved
++#define EM_res154        154 // Reserved
++#define EM_res155        155 // Reserved
++#define EM_res156        156 // Reserved
++#define EM_res157        157 // Reserved
++#define EM_res158        158 // Reserved
++#define EM_res159        159 // Reserved
++#define EM_MMDSP_PLUS    160 // STMicroelectronics 64bit VLIW Data Signal Processor
++#define EM_CYPRESS_M8C   161 // Cypress M8C microprocessor
++#define EM_R32C          162 // Renesas R32C series microprocessors
++#define EM_TRIMEDIA      163 // NXP Semiconductors TriMedia architecture family
++#define EM_QDSP6         164 // QUALCOMM DSP6 Processor
++#define EM_8051          165 // Intel 8051 and variants
++#define EM_STXP7X        166 // STMicroelectronics STxP7x family
++#define EM_NDS32 \
++	167 // Andes Technology compact code size embedded RISC processor family
++#define EM_ECOG1         168 // Cyan Technology eCOG1X family
++#define EM_ECOG1X        168 // Cyan Technology eCOG1X family
++#define EM_MAXQ30        169 // Dallas Semiconductor MAXQ30 Core Micro-controllers
++#define EM_XIMO16        170 // New Japan Radio (NJR) 16-bit DSP Processor
++#define EM_MANIK         171 // M2000 Reconfigurable RISC Microprocessor
++#define EM_CRAYNV2       172 // Cray Inc. NV2 vector architecture
++#define EM_RX            173 // Renesas RX family
++#define EM_METAG         174 // Imagination Technologies META processor architecture
++#define EM_MCST_ELBRUS   175 // MCST Elbrus general purpose hardware architecture
++#define EM_ECOG16        176 // Cyan Technology eCOG16 family
++#define EM_CR16          177 // National Semiconductor CompactRISC 16-bit processor
++#define EM_ETPU          178 // Freescale Extended Time Processing Unit
++#define EM_SLE9X         179 // Infineon Technologies SLE9X core
++#define EM_L1OM          180 // Intel L1OM
++#define EM_INTEL181      181 // Reserved by Intel
++#define EM_INTEL182      182 // Reserved by Intel
++#define EM_res183        183 // Reserved by ARM
++#define EM_res184        184 // Reserved by ARM
++#define EM_AVR32         185 // Atmel Corporation 32-bit microprocessor family
++#define EM_STM8          186 // STMicroeletronics STM8 8-bit microcontroller
++#define EM_TILE64        187 // Tilera TILE64 multicore architecture family
++#define EM_TILEPRO       188 // Tilera TILEPro multicore architecture family
++#define EM_MICROBLAZE    189 // Xilinx MicroBlaze 32-bit RISC soft processor core
++#define EM_CUDA          190 // NVIDIA CUDA architecture
++#define EM_TILEGX        191 // Tilera TILE-Gx multicore architecture family
++#define EM_CLOUDSHIELD   192 // CloudShield architecture family
++#define EM_COREA_1ST     193 // KIPO-KAIST Core-A 1st generation processor family
++#define EM_COREA_2ND     194 // KIPO-KAIST Core-A 2nd generation processor family
++#define EM_ARC_COMPACT2  195 // Synopsys ARCompact V2
++#define EM_OPEN8         196 // Open8 8-bit RISC soft processor core
++#define EM_RL78          197 // Renesas RL78 family
++#define EM_VIDEOCORE5    198 // Broadcom VideoCore V processor
++#define EM_78KOR         199 // Renesas 78KOR family
++#define EM_56800EX       200 // Freescale 56800EX Digital Signal Controller (DSC)
++#define EM_BA1           201 // Beyond BA1 CPU architecture
++#define EM_BA2           202 // Beyond BA2 CPU architecture
++#define EM_XCORE         203 // XMOS xCORE processor family
++#define EM_MCHP_PIC      204 // Microchip 8-bit PIC(r) family
++#define EM_INTEL205      205 // Reserved by Intel
++#define EM_INTEL206      206 // Reserved by Intel
++#define EM_INTEL207      207 // Reserved by Intel
++#define EM_INTEL208      208 // Reserved by Intel
++#define EM_INTEL209      209 // Reserved by Intel
++#define EM_KM32          210 // KM211 KM32 32-bit processor
++#define EM_KMX32         211 // KM211 KMX32 32-bit processor
++#define EM_KMX16         212 // KM211 KMX16 16-bit processor
++#define EM_KMX8          213 // KM211 KMX8 8-bit processor
++#define EM_KVARC         214 // KM211 KVARC processor
++#define EM_CDP           215 // Paneve CDP architecture family
++#define EM_COGE          216 // Cognitive Smart Memory Processor
++#define EM_COOL          217 // iCelero CoolEngine
++#define EM_NORC          218 // Nanoradio Optimized RISC
++#define EM_CSR_KALIMBA   219 // CSR Kalimba architecture family
++#define EM_Z80           220 // Zilog Z80
++#define EM_VISIUM        221 // Controls and Data Services VISIUMcore processor
++#define EM_FT32          222 // FTDI Chip FT32 high performance 32-bit RISC architecture
++#define EM_MOXIE         223 // Moxie processor family
++#define EM_AMDGPU        224 // AMD GPU architecture
++#define EM_RISCV         243 // RISC-V
++#define EM_LANAI         244 // Lanai processor
++#define EM_CEVA          245 // CEVA Processor Architecture Family
++#define EM_CEVA_X2       246 // CEVA X2 Processor Family
++#define EM_BPF           247 // Linux BPF – in-kernel virtual machine
++#define EM_GRAPHCORE_IPU 248 // Graphcore Intelligent Processing Unit
++#define EM_IMG1          249 // Imagination Technologies
++#define EM_NFP           250 // Netronome Flow Processor (P)
++#define EM_CSKY          252 // C-SKY processor family
++
++// File version
++#define EV_NONE    0
++#define EV_CURRENT 1
++
++// Identification index
++#define EI_MAG0       0
++#define EI_MAG1       1
++#define EI_MAG2       2
++#define EI_MAG3       3
++#define EI_CLASS      4
++#define EI_DATA       5
++#define EI_VERSION    6
++#define EI_OSABI      7
++#define EI_ABIVERSION 8
++#define EI_PAD        9
++#define EI_NIDENT     16
++
++// Magic number
++#define ELFMAG0 0x7F
++#define ELFMAG1 'E'
++#define ELFMAG2 'L'
++#define ELFMAG3 'F'
++
++// File class
++#define ELFCLASSNONE 0
++#define ELFCLASS32   1
++#define ELFCLASS64   2
++
++// Encoding
++#define ELFDATANONE 0
++#define ELFDATA2LSB 1
++#define ELFDATA2MSB 2
++
++// OS extensions
++#define ELFOSABI_NONE    0  // No extensions or unspecified
++#define ELFOSABI_HPUX    1  // Hewlett-Packard HP-UX
++#define ELFOSABI_NETBSD  2  // NetBSD
++#define ELFOSABI_LINUX   3  // Linux
++#define ELFOSABI_SOLARIS 6  // Sun Solaris
++#define ELFOSABI_AIX     7  // AIX
++#define ELFOSABI_IRIX    8  // IRIX
++#define ELFOSABI_FREEBSD 9  // FreeBSD
++#define ELFOSABI_TRU64   10 // Compaq TRU64 UNIX
++#define ELFOSABI_MODESTO 11 // Novell Modesto
++#define ELFOSABI_OPENBSD 12 // Open BSD
++#define ELFOSABI_OPENVMS 13 // Open VMS
++#define ELFOSABI_NSK     14 // Hewlett-Packard Non-Stop Kernel
++#define ELFOSABI_AROS    15 // Amiga Research OS
++#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS
++//                             64-255 Architecture-specific value range
++#define ELFOSABI_AMDGPU_HSA \
++	64 // AMDGPU OS for HSA compatible compute 	// kernels.
++#define ELFOSABI_AMDGPU_PAL \
++	65 // AMDGPU OS for AMD PAL compatible graphics  // shaders and compute kernels.
++#define ELFOSABI_AMDGPU_MESA3D \
++	66 // AMDGPU OS for Mesa3D compatible graphics 	// shaders and compute kernels.
++
++// AMDGPU specific e_flags
++#define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask.
++#define EF_AMDGPU_XNACK \
++	0x100 // Indicates if the XNACK target feature is   // enabled for all code contained in the ELF.
++// AMDGPU processors
++#define EF_AMDGPU_MACH_NONE                0x000 // Unspecified processor.
++#define EF_AMDGPU_MACH_R600_R600           0x001
++#define EF_AMDGPU_MACH_R600_R630           0x002
++#define EF_AMDGPU_MACH_R600_RS880          0x003
++#define EF_AMDGPU_MACH_R600_RV670          0x004
++#define EF_AMDGPU_MACH_R600_RV710          0x005
++#define EF_AMDGPU_MACH_R600_RV730          0x006
++#define EF_AMDGPU_MACH_R600_RV770          0x007
++#define EF_AMDGPU_MACH_R600_CEDAR          0x008
++#define EF_AMDGPU_MACH_R600_CYPRESS        0x009
++#define EF_AMDGPU_MACH_R600_JUNIPER        0x00a
++#define EF_AMDGPU_MACH_R600_REDWOOD        0x00b
++#define EF_AMDGPU_MACH_R600_SUMO           0x00c
++#define EF_AMDGPU_MACH_R600_BARTS          0x00d
++#define EF_AMDGPU_MACH_R600_CAICOS         0x00e
++#define EF_AMDGPU_MACH_R600_CAYMAN         0x00f
++#define EF_AMDGPU_MACH_R600_TURKS          0x010
++#define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011
++#define EF_AMDGPU_MACH_R600_RESERVED_LAST  0x01f
++#define EF_AMDGPU_MACH_R600_FIRST          EF_AMDGPU_MACH_R600_R600
++#define EF_AMDGPU_MACH_R600_LAST           EF_AMDGPU_MACH_R600_TURKS
++#define EF_AMDGPU_MACH_AMDGCN_GFX600       0x020
++#define EF_AMDGPU_MACH_AMDGCN_GFX601       0x021
++#define EF_AMDGPU_MACH_AMDGCN_GFX700       0x022
++#define EF_AMDGPU_MACH_AMDGCN_GFX701       0x023
++#define EF_AMDGPU_MACH_AMDGCN_GFX702       0x024
++#define EF_AMDGPU_MACH_AMDGCN_GFX703       0x025
++#define EF_AMDGPU_MACH_AMDGCN_GFX704       0x026
++#define EF_AMDGPU_MACH_AMDGCN_GFX801       0x028
++#define EF_AMDGPU_MACH_AMDGCN_GFX802       0x029
++#define EF_AMDGPU_MACH_AMDGCN_GFX803       0x02a
++#define EF_AMDGPU_MACH_AMDGCN_GFX810       0x02b
++#define EF_AMDGPU_MACH_AMDGCN_GFX900       0x02c
++#define EF_AMDGPU_MACH_AMDGCN_GFX902       0x02d
++#define EF_AMDGPU_MACH_AMDGCN_GFX904       0x02e
++#define EF_AMDGPU_MACH_AMDGCN_GFX906       0x02f
++#define EF_AMDGPU_MACH_AMDGCN_RESERVED0    0x027
++#define EF_AMDGPU_MACH_AMDGCN_RESERVED1    0x030
++#define EF_AMDGPU_MACH_AMDGCN_FIRST        EF_AMDGPU_MACH_AMDGCN_GFX600
++#define EF_AMDGPU_MACH_AMDGCN_LAST         EF_AMDGPU_MACH_AMDGCN_GFX906
++
++/////////////////////
++// Sections constants
++
++// Section indexes
++#define SHN_UNDEF     0
++#define SHN_LORESERVE 0xFF00
++#define SHN_LOPROC    0xFF00
++#define SHN_HIPROC    0xFF1F
++#define SHN_LOOS      0xFF20
++#define SHN_HIOS      0xFF3F
++#define SHN_ABS       0xFFF1
++#define SHN_COMMON    0xFFF2
++#define SHN_XINDEX    0xFFFF
++#define SHN_HIRESERVE 0xFFFF
++
++// Section types
++#define SHT_NULL          0
++#define SHT_PROGBITS      1
++#define SHT_SYMTAB        2
++#define SHT_STRTAB        3
++#define SHT_RELA          4
++#define SHT_HASH          5
++#define SHT_DYNAMIC       6
++#define SHT_NOTE          7
++#define SHT_NOBITS        8
++#define SHT_REL           9
++#define SHT_SHLIB         10
++#define SHT_DYNSYM        11
++#define SHT_INIT_ARRAY    14
++#define SHT_FINI_ARRAY    15
++#define SHT_PREINIT_ARRAY 16
++#define SHT_GROUP         17
++#define SHT_SYMTAB_SHNDX  18
++#define SHT_LOOS          0x60000000
++#define SHT_HIOS          0x6fffffff
++#define SHT_LOPROC        0x70000000
++#define SHT_HIPROC        0x7FFFFFFF
++#define SHT_LOUSER        0x80000000
++#define SHT_HIUSER        0xFFFFFFFF
++
++// Section attribute flags
++#define SHF_WRITE            0x1
++#define SHF_ALLOC            0x2
++#define SHF_EXECINSTR        0x4
++#define SHF_MERGE            0x10
++#define SHF_STRINGS          0x20
++#define SHF_INFO_LINK        0x40
++#define SHF_LINK_ORDER       0x80
++#define SHF_OS_NONCONFORMING 0x100
++#define SHF_GROUP            0x200
++#define SHF_TLS              0x400
++#define SHF_MASKOS           0x0ff00000
++#define SHF_MASKPROC         0xF0000000
++
++// Section group flags
++#define GRP_COMDAT   0x1
++#define GRP_MASKOS   0x0ff00000
++#define GRP_MASKPROC 0xf0000000
++
++// Symbol binding
++#define STB_LOCAL    0
++#define STB_GLOBAL   1
++#define STB_WEAK     2
++#define STB_LOOS     10
++#define STB_HIOS     12
++#define STB_MULTIDEF 13
++#define STB_LOPROC   13
++#define STB_HIPROC   15
++
++// Note types
++#define NT_AMDGPU_METADATA         1
++#define NT_AMD_AMDGPU_HSA_METADATA 10
++#define NT_AMD_AMDGPU_ISA          11
++#define NT_AMD_AMDGPU_PAL_METADATA 12
++
++// Symbol types
++#define STT_NOTYPE            0
++#define STT_OBJECT            1
++#define STT_FUNC              2
++#define STT_SECTION           3
++#define STT_FILE              4
++#define STT_COMMON            5
++#define STT_TLS               6
++#define STT_LOOS              10
++#define STT_AMDGPU_HSA_KERNEL 10
++#define STT_HIOS              12
++#define STT_LOPROC            13
++#define STT_HIPROC            15
++
++// Symbol visibility
++#define STV_DEFAULT   0
++#define STV_INTERNAL  1
++#define STV_HIDDEN    2
++#define STV_PROTECTED 3
++
++// Undefined name
++#define STN_UNDEF 0
++
++// Relocation types
++#define R_386_NONE               0
++#define R_X86_64_NONE            0
++#define R_AMDGPU_NONE            0
++#define R_386_32                 1
++#define R_X86_64_64              1
++#define R_AMDGPU_ABS32_LO        1
++#define R_386_PC32               2
++#define R_X86_64_PC32            2
++#define R_AMDGPU_ABS32_HI        2
++#define R_386_GOT32              3
++#define R_X86_64_GOT32           3
++#define R_AMDGPU_ABS64           3
++#define R_386_PLT32              4
++#define R_X86_64_PLT32           4
++#define R_AMDGPU_REL32           4
++#define R_386_COPY               5
++#define R_X86_64_COPY            5
++#define R_AMDGPU_REL64           5
++#define R_386_GLOB_DAT           6
++#define R_X86_64_GLOB_DAT        6
++#define R_AMDGPU_ABS32           6
++#define R_386_JMP_SLOT           7
++#define R_X86_64_JUMP_SLOT       7
++#define R_AMDGPU_GOTPCREL        7
++#define R_386_RELATIVE           8
++#define R_X86_64_RELATIVE        8
++#define R_AMDGPU_GOTPCREL32_LO   8
++#define R_386_GOTOFF             9
++#define R_X86_64_GOTPCREL        9
++#define R_AMDGPU_GOTPCREL32_HI   9
++#define R_386_GOTPC              10
++#define R_X86_64_32              10
++#define R_AMDGPU_REL32_LO        10
++#define R_386_32PLT              11
++#define R_X86_64_32S             11
++#define R_AMDGPU_REL32_HI        11
++#define R_X86_64_16              12
++#define R_X86_64_PC16            13
++#define R_AMDGPU_RELATIVE64      13
++#define R_386_TLS_TPOFF          14
++#define R_X86_64_8               14
++#define R_386_TLS_IE             15
++#define R_X86_64_PC8             15
++#define R_386_TLS_GOTIE          16
++#define R_X86_64_DTPMOD64        16
++#define R_386_TLS_LE             17
++#define R_X86_64_DTPOFF64        17
++#define R_386_TLS_GD             18
++#define R_X86_64_TPOFF64         18
++#define R_386_TLS_LDM            19
++#define R_X86_64_TLSGD           19
++#define R_386_16                 20
++#define R_X86_64_TLSLD           20
++#define R_386_PC16               21
++#define R_X86_64_DTPOFF32        21
++#define R_386_8                  22
++#define R_X86_64_GOTTPOFF        22
++#define R_386_PC8                23
++#define R_X86_64_TPOFF32         23
++#define R_386_TLS_GD_32          24
++#define R_X86_64_PC64            24
++#define R_386_TLS_GD_PUSH        25
++#define R_X86_64_GOTOFF64        25
++#define R_386_TLS_GD_CALL        26
++#define R_X86_64_GOTPC32         26
++#define R_386_TLS_GD_POP         27
++#define R_X86_64_GOT64           27
++#define R_386_TLS_LDM_32         28
++#define R_X86_64_GOTPCREL64      28
++#define R_386_TLS_LDM_PUSH       29
++#define R_X86_64_GOTPC64         29
++#define R_386_TLS_LDM_CALL       30
++#define R_X86_64_GOTPLT64        30
++#define R_386_TLS_LDM_POP        31
++#define R_X86_64_PLTOFF64        31
++#define R_386_TLS_LDO_32         32
++#define R_386_TLS_IE_32          33
++#define R_386_TLS_LE_32          34
++#define R_X86_64_GOTPC32_TLSDESC 34
++#define R_386_TLS_DTPMOD32       35
++#define R_X86_64_TLSDESC_CALL    35
++#define R_386_TLS_DTPOFF32       36
++#define R_X86_64_TLSDESC         36
++#define R_386_TLS_TPOFF32        37
++#define R_X86_64_IRELATIVE       37
++#define R_386_SIZE32             38
++#define R_386_TLS_GOTDESC        39
++#define R_386_TLS_DESC_CALL      40
++#define R_386_TLS_DESC           41
++#define R_386_IRELATIVE          42
++#define R_386_GOT32X             43
++#define R_X86_64_GNU_VTINHERIT   250
++#define R_X86_64_GNU_VTENTRY     251
++
++// Segment types
++#define PT_NULL    0
++#define PT_LOAD    1
++#define PT_DYNAMIC 2
++#define PT_INTERP  3
++#define PT_NOTE    4
++#define PT_SHLIB   5
++#define PT_PHDR    6
++#define PT_TLS     7
++#define PT_LOOS    0x60000000
++#define PT_HIOS    0x6fffffff
++#define PT_LOPROC  0x70000000
++#define PT_HIPROC  0x7FFFFFFF
++
++// Segment flags
++#define PF_X        1          // Execute
++#define PF_W        2          // Write
++#define PF_R        4          // Read
++#define PF_MASKOS   0x0ff00000 // Unspecified
++#define PF_MASKPROC 0xf0000000 // Unspecified
++
++// Dynamic Array Tags
++#define DT_NULL            0
++#define DT_NEEDED          1
++#define DT_PLTRELSZ        2
++#define DT_PLTGOT          3
++#define DT_HASH            4
++#define DT_STRTAB          5
++#define DT_SYMTAB          6
++#define DT_RELA            7
++#define DT_RELASZ          8
++#define DT_RELAENT         9
++#define DT_STRSZ           10
++#define DT_SYMENT          11
++#define DT_INIT            12
++#define DT_FINI            13
++#define DT_SONAME          14
++#define DT_RPATH           15
++#define DT_SYMBOLIC        16
++#define DT_REL             17
++#define DT_RELSZ           18
++#define DT_RELENT          19
++#define DT_PLTREL          20
++#define DT_DEBUG           21
++#define DT_TEXTREL         22
++#define DT_JMPREL          23
++#define DT_BIND_NOW        24
++#define DT_INIT_ARRAY      25
++#define DT_FINI_ARRAY      26
++#define DT_INIT_ARRAYSZ    27
++#define DT_FINI_ARRAYSZ    28
++#define DT_RUNPATH         29
++#define DT_FLAGS           30
++#define DT_ENCODING        32
++#define DT_PREINIT_ARRAY   32
++#define DT_PREINIT_ARRAYSZ 33
++#define DT_MAXPOSTAGS      34
++#define DT_LOOS            0x6000000D
++#define DT_HIOS            0x6ffff000
++#define DT_LOPROC          0x70000000
++#define DT_HIPROC          0x7FFFFFFF
++
++// DT_FLAGS values
++#define DF_ORIGIN     0x1
++#define DF_SYMBOLIC   0x2
++#define DF_TEXTREL    0x4
++#define DF_BIND_NOW   0x8
++#define DF_STATIC_TLS 0x10
++
++// ELF file header
++struct Elf32_Ehdr
++{
++	unsigned char e_ident[EI_NIDENT];
++	Elf_Half      e_type;
++	Elf_Half      e_machine;
++	Elf_Word      e_version;
++	Elf32_Addr    e_entry;
++	Elf32_Off     e_phoff;
++	Elf32_Off     e_shoff;
++	Elf_Word      e_flags;
++	Elf_Half      e_ehsize;
++	Elf_Half      e_phentsize;
++	Elf_Half      e_phnum;
++	Elf_Half      e_shentsize;
++	Elf_Half      e_shnum;
++	Elf_Half      e_shstrndx;
++};
++
++struct Elf64_Ehdr
++{
++	unsigned char e_ident[EI_NIDENT];
++	Elf_Half      e_type;
++	Elf_Half      e_machine;
++	Elf_Word      e_version;
++	Elf64_Addr    e_entry;
++	Elf64_Off     e_phoff;
++	Elf64_Off     e_shoff;
++	Elf_Word      e_flags;
++	Elf_Half      e_ehsize;
++	Elf_Half      e_phentsize;
++	Elf_Half      e_phnum;
++	Elf_Half      e_shentsize;
++	Elf_Half      e_shnum;
++	Elf_Half      e_shstrndx;
++};
++
++// Section header
++struct Elf32_Shdr
++{
++	Elf_Word   sh_name;
++	Elf_Word   sh_type;
++	Elf_Word   sh_flags;
++	Elf32_Addr sh_addr;
++	Elf32_Off  sh_offset;
++	Elf_Word   sh_size;
++	Elf_Word   sh_link;
++	Elf_Word   sh_info;
++	Elf_Word   sh_addralign;
++	Elf_Word   sh_entsize;
++};
++
++struct Elf64_Shdr
++{
++	Elf_Word   sh_name;
++	Elf_Word   sh_type;
++	Elf_Xword  sh_flags;
++	Elf64_Addr sh_addr;
++	Elf64_Off  sh_offset;
++	Elf_Xword  sh_size;
++	Elf_Word   sh_link;
++	Elf_Word   sh_info;
++	Elf_Xword  sh_addralign;
++	Elf_Xword  sh_entsize;
++};
++
++// Segment header
++struct Elf32_Phdr
++{
++	Elf_Word   p_type;
++	Elf32_Off  p_offset;
++	Elf32_Addr p_vaddr;
++	Elf32_Addr p_paddr;
++	Elf_Word   p_filesz;
++	Elf_Word   p_memsz;
++	Elf_Word   p_flags;
++	Elf_Word   p_align;
++};
++
++struct Elf64_Phdr
++{
++	Elf_Word   p_type;
++	Elf_Word   p_flags;
++	Elf64_Off  p_offset;
++	Elf64_Addr p_vaddr;
++	Elf64_Addr p_paddr;
++	Elf_Xword  p_filesz;
++	Elf_Xword  p_memsz;
++	Elf_Xword  p_align;
++};
++
++// Symbol table entry
++struct Elf32_Sym
++{
++	Elf_Word      st_name;
++	Elf32_Addr    st_value;
++	Elf_Word      st_size;
++	unsigned char st_info;
++	unsigned char st_other;
++	Elf_Half      st_shndx;
++};
++
++struct Elf64_Sym
++{
++	Elf_Word      st_name;
++	unsigned char st_info;
++	unsigned char st_other;
++	Elf_Half      st_shndx;
++	Elf64_Addr    st_value;
++	Elf_Xword     st_size;
++};
++
++#define ELF_ST_BIND( i )    ( ( i ) >> 4 )
++#define ELF_ST_TYPE( i )    ( (i)&0xf )
++#define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( (t)&0xf ) )
++
++#define ELF_ST_VISIBILITY( o ) ( (o)&0x3 )
++
++// Relocation entries
++struct Elf32_Rel
++{
++	Elf32_Addr r_offset;
++	Elf_Word   r_info;
++};
++
++struct Elf32_Rela
++{
++	Elf32_Addr r_offset;
++	Elf_Word   r_info;
++	Elf_Sword  r_addend;
++};
++
++struct Elf64_Rel
++{
++	Elf64_Addr r_offset;
++	Elf_Xword  r_info;
++};
++
++struct Elf64_Rela
++{
++	Elf64_Addr r_offset;
++	Elf_Xword  r_info;
++	Elf_Sxword r_addend;
++};
++
++#define ELF32_R_SYM( i )     ( ( i ) >> 8 )
++#define ELF32_R_TYPE( i )    ( (unsigned char)( i ) )
++#define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) )
++
++#define ELF64_R_SYM( i )  ( ( i ) >> 32 )
++#define ELF64_R_TYPE( i ) ( (i)&0xffffffffL )
++#define ELF64_R_INFO( s, t ) \
++	( ( ( ( int64_t )( s ) ) << 32 ) + ( (t)&0xffffffffL ) )
++
++// Dynamic structure
++struct Elf32_Dyn
++{
++	Elf_Sword d_tag;
++	union {
++		Elf_Word   d_val;
++		Elf32_Addr d_ptr;
++	} d_un;
++};
++
++struct Elf64_Dyn
++{
++	Elf_Sxword d_tag;
++	union {
++		Elf_Xword  d_val;
++		Elf64_Addr d_ptr;
++	} d_un;
++};
++
++} // namespace ELFIO
++
++#endif // ELFTYPES_H
++
++/*** End of inlined file: elf_types.hpp ***/
++
++
++/*** Start of inlined file: elfio_version.hpp ***/
++#define ELFIO_VERSION "3.8"
++
++/*** End of inlined file: elfio_version.hpp ***/
++
++
++/*** Start of inlined file: elfio_utils.hpp ***/
++#ifndef ELFIO_UTILS_HPP
++#define ELFIO_UTILS_HPP
++
++#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
++	TYPE get_##NAME() const { return ( *convertor )( FIELD ); }
++#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
++	void set_##NAME( TYPE value )             \
++	{                                         \
++		FIELD = value;                        \
++		FIELD = ( *convertor )( FIELD );      \
++	}
++#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD )               \
++	TYPE get_##NAME() const { return ( *convertor )( FIELD ); } \
++	void set_##NAME( TYPE value )                               \
++	{                                                           \
++		FIELD = value;                                          \
++		FIELD = ( *convertor )( FIELD );                        \
++	}
++
++#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0
++
++#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \
++	virtual void set_##NAME( TYPE value ) = 0
++
++#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
++	virtual TYPE get_##NAME() const       = 0;  \
++	virtual void set_##NAME( TYPE value ) = 0
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++class endianess_convertor
++{
++  public:
++	//------------------------------------------------------------------------------
++	endianess_convertor() { need_conversion = false; }
++
++	//------------------------------------------------------------------------------
++	void setup( unsigned char elf_file_encoding )
++	{
++		need_conversion = ( elf_file_encoding != get_host_encoding() );
++	}
++
++	//------------------------------------------------------------------------------
++	uint64_t operator()( uint64_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		value = ( ( value & 0x00000000000000FFull ) << 56 ) |
++				( ( value & 0x000000000000FF00ull ) << 40 ) |
++				( ( value & 0x0000000000FF0000ull ) << 24 ) |
++				( ( value & 0x00000000FF000000ull ) << 8 ) |
++				( ( value & 0x000000FF00000000ull ) >> 8 ) |
++				( ( value & 0x0000FF0000000000ull ) >> 24 ) |
++				( ( value & 0x00FF000000000000ull ) >> 40 ) |
++				( ( value & 0xFF00000000000000ull ) >> 56 );
++
++		return value;
++	}
++
++	//------------------------------------------------------------------------------
++	int64_t operator()( int64_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		return ( int64_t )( *this )( (uint64_t)value );
++	}
++
++	//------------------------------------------------------------------------------
++	uint32_t operator()( uint32_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		value =
++			( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
++			( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );
++
++		return value;
++	}
++
++	//------------------------------------------------------------------------------
++	int32_t operator()( int32_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		return ( int32_t )( *this )( (uint32_t)value );
++	}
++
++	//------------------------------------------------------------------------------
++	uint16_t operator()( uint16_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		value = ( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 );
++
++		return value;
++	}
++
++	//------------------------------------------------------------------------------
++	int16_t operator()( int16_t value ) const
++	{
++		if ( !need_conversion ) {
++			return value;
++		}
++		return ( int16_t )( *this )( (uint16_t)value );
++	}
++
++	//------------------------------------------------------------------------------
++	int8_t operator()( int8_t value ) const { return value; }
++
++	//------------------------------------------------------------------------------
++	uint8_t operator()( uint8_t value ) const { return value; }
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	unsigned char get_host_encoding() const
++	{
++		static const int tmp = 1;
++		if ( 1 == *(const char*)&tmp ) {
++			return ELFDATA2LSB;
++		}
++		else {
++			return ELFDATA2MSB;
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	bool need_conversion;
++};
++
++//------------------------------------------------------------------------------
++inline uint32_t elf_hash( const unsigned char* name )
++{
++	uint32_t h = 0, g;
++	while ( *name ) {
++		h = ( h << 4 ) + *name++;
++		g = h & 0xf0000000;
++		if ( g != 0 )
++			h ^= g >> 24;
++		h &= ~g;
++	}
++	return h;
++}
++
++} // namespace ELFIO
++
++#endif // ELFIO_UTILS_HPP
++
++/*** End of inlined file: elfio_utils.hpp ***/
++
++
++/*** Start of inlined file: elfio_header.hpp ***/
++#ifndef ELF_HEADER_HPP
++#define ELF_HEADER_HPP
++
++#include <iostream>
++
++namespace ELFIO {
++
++class elf_header
++{
++  public:
++	virtual ~elf_header(){};
++	virtual bool load( std::istream& stream )       = 0;
++	virtual bool save( std::ostream& stream ) const = 0;
++
++	// ELF header functions
++	ELFIO_GET_ACCESS_DECL( unsigned char, class );
++	ELFIO_GET_ACCESS_DECL( unsigned char, elf_version );
++	ELFIO_GET_ACCESS_DECL( unsigned char, encoding );
++	ELFIO_GET_ACCESS_DECL( Elf_Half, header_size );
++	ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size );
++	ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size );
++
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version );
++	ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi );
++	ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index );
++};
++
++template <class T> struct elf_header_impl_types;
++template <> struct elf_header_impl_types<Elf32_Ehdr>
++{
++	typedef Elf32_Phdr         Phdr_type;
++	typedef Elf32_Shdr         Shdr_type;
++	static const unsigned char file_class = ELFCLASS32;
++};
++template <> struct elf_header_impl_types<Elf64_Ehdr>
++{
++	typedef Elf64_Phdr         Phdr_type;
++	typedef Elf64_Shdr         Shdr_type;
++	static const unsigned char file_class = ELFCLASS64;
++};
++
++template <class T> class elf_header_impl : public elf_header
++{
++  public:
++	//------------------------------------------------------------------------------
++	elf_header_impl( endianess_convertor* convertor_, unsigned char encoding )
++	{
++		convertor = convertor_;
++
++		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
++					 '\0' );
++
++		header.e_ident[EI_MAG0]    = ELFMAG0;
++		header.e_ident[EI_MAG1]    = ELFMAG1;
++		header.e_ident[EI_MAG2]    = ELFMAG2;
++		header.e_ident[EI_MAG3]    = ELFMAG3;
++		header.e_ident[EI_CLASS]   = elf_header_impl_types<T>::file_class;
++		header.e_ident[EI_DATA]    = encoding;
++		header.e_ident[EI_VERSION] = EV_CURRENT;
++		header.e_version           = ( *convertor )( (Elf_Word)EV_CURRENT );
++		header.e_ehsize            = ( sizeof( header ) );
++		header.e_ehsize            = ( *convertor )( header.e_ehsize );
++		header.e_shstrndx          = ( *convertor )( (Elf_Half)1 );
++		header.e_phentsize =
++			sizeof( typename elf_header_impl_types<T>::Phdr_type );
++		header.e_shentsize =
++			sizeof( typename elf_header_impl_types<T>::Shdr_type );
++		header.e_phentsize = ( *convertor )( header.e_phentsize );
++		header.e_shentsize = ( *convertor )( header.e_shentsize );
++	}
++
++	//------------------------------------------------------------------------------
++	bool load( std::istream& stream )
++	{
++		stream.seekg( 0 );
++		stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
++
++		return ( stream.gcount() == sizeof( header ) );
++	}
++
++	//------------------------------------------------------------------------------
++	bool save( std::ostream& stream ) const
++	{
++		stream.seekp( 0 );
++		stream.write( reinterpret_cast<const char*>( &header ),
++					  sizeof( header ) );
++
++		return stream.good();
++	}
++
++	//------------------------------------------------------------------------------
++	// ELF header functions
++	ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] );
++	ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] );
++	ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] );
++	ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize );
++	ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize );
++	ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize );
++
++	ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version );
++	ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] );
++	ELFIO_GET_SET_ACCESS( unsigned char,
++						  abi_version,
++						  header.e_ident[EI_ABIVERSION] );
++	ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type );
++	ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine );
++	ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags );
++	ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx );
++	ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry );
++	ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum );
++	ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff );
++	ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum );
++	ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff );
++
++  private:
++	T                    header;
++	endianess_convertor* convertor;
++};
++
++} // namespace ELFIO
++
++#endif // ELF_HEADER_HPP
++
++/*** End of inlined file: elfio_header.hpp ***/
++
++
++/*** Start of inlined file: elfio_section.hpp ***/
++#ifndef ELFIO_SECTION_HPP
++#define ELFIO_SECTION_HPP
++
++#include <string>
++#include <iostream>
++#include <new>
++
++namespace ELFIO {
++
++class section
++{
++	friend class elfio;
++
++  public:
++	virtual ~section(){};
++
++	ELFIO_GET_ACCESS_DECL( Elf_Half, index );
++	ELFIO_GET_SET_ACCESS_DECL( std::string, name );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset );
++	ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
++
++	virtual const char* get_data() const                                = 0;
++	virtual void        set_data( const char* pData, Elf_Word size )    = 0;
++	virtual void        set_data( const std::string& data )             = 0;
++	virtual void        append_data( const char* pData, Elf_Word size ) = 0;
++	virtual void        append_data( const std::string& data )          = 0;
++	virtual size_t      get_stream_size() const                         = 0;
++	virtual void        set_stream_size( size_t value )                 = 0;
++
++  protected:
++	ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
++	ELFIO_SET_ACCESS_DECL( Elf_Half, index );
++
++	virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
++	virtual void save( std::ostream&  stream,
++					   std::streampos header_offset,
++					   std::streampos data_offset )                         = 0;
++	virtual bool is_address_initialized() const                             = 0;
++};
++
++template <class T> class section_impl : public section
++{
++  public:
++	//------------------------------------------------------------------------------
++	section_impl( const endianess_convertor* convertor_ )
++		: convertor( convertor_ )
++	{
++		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
++					 '\0' );
++		is_address_set = false;
++		data           = 0;
++		data_size      = 0;
++		index          = 0;
++		stream_size    = 0;
++	}
++
++	//------------------------------------------------------------------------------
++	~section_impl() { delete[] data; }
++
++	//------------------------------------------------------------------------------
++	// Section info functions
++	ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
++	ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
++	ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
++	ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
++	ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_index() const { return index; }
++
++	//------------------------------------------------------------------------------
++	std::string get_name() const { return name; }
++
++	//------------------------------------------------------------------------------
++	void set_name( std::string name_ ) { name = name_; }
++
++	//------------------------------------------------------------------------------
++	void set_address( Elf64_Addr value )
++	{
++		header.sh_addr = value;
++		header.sh_addr = ( *convertor )( header.sh_addr );
++		is_address_set = true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool is_address_initialized() const { return is_address_set; }
++
++	//------------------------------------------------------------------------------
++	const char* get_data() const { return data; }
++
++	//------------------------------------------------------------------------------
++	void set_data( const char* raw_data, Elf_Word size )
++	{
++		if ( get_type() != SHT_NOBITS ) {
++			delete[] data;
++			data = new ( std::nothrow ) char[size];
++			if ( 0 != data && 0 != raw_data ) {
++				data_size = size;
++				std::copy( raw_data, raw_data + size, data );
++			}
++			else {
++				data_size = 0;
++			}
++		}
++
++		set_size( data_size );
++	}
++
++	//------------------------------------------------------------------------------
++	void set_data( const std::string& str_data )
++	{
++		return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
++	}
++
++	//------------------------------------------------------------------------------
++	void append_data( const char* raw_data, Elf_Word size )
++	{
++		if ( get_type() != SHT_NOBITS ) {
++			if ( get_size() + size < data_size ) {
++				std::copy( raw_data, raw_data + size, data + get_size() );
++			}
++			else {
++				data_size      = 2 * ( data_size + size );
++				char* new_data = new ( std::nothrow ) char[data_size];
++
++				if ( 0 != new_data ) {
++					std::copy( data, data + get_size(), new_data );
++					std::copy( raw_data, raw_data + size,
++							   new_data + get_size() );
++					delete[] data;
++					data = new_data;
++				}
++				else {
++					size = 0;
++				}
++			}
++			set_size( get_size() + size );
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void append_data( const std::string& str_data )
++	{
++		return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
++	}
++
++	//------------------------------------------------------------------------------
++  protected:
++	//------------------------------------------------------------------------------
++	ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
++
++	//------------------------------------------------------------------------------
++	void set_index( Elf_Half value ) { index = value; }
++
++	//------------------------------------------------------------------------------
++	void load( std::istream& stream, std::streampos header_offset )
++	{
++		std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
++					 '\0' );
++
++		stream.seekg( 0, stream.end );
++		set_stream_size( stream.tellg() );
++
++		stream.seekg( header_offset );
++		stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
++
++		Elf_Xword size = get_size();
++		if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() &&
++			 size < get_stream_size() ) {
++			data = new ( std::nothrow ) char[size + 1];
++
++			if ( ( 0 != size ) && ( 0 != data ) ) {
++				stream.seekg( ( *convertor )( header.sh_offset ) );
++				stream.read( data, size );
++				data[size] = 0; // Ensure data is ended with 0 to avoid oob read
++				data_size  = size;
++			}
++			else {
++				data_size = 0;
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void save( std::ostream&  stream,
++			   std::streampos header_offset,
++			   std::streampos data_offset )
++	{
++		if ( 0 != get_index() ) {
++			header.sh_offset = data_offset;
++			header.sh_offset = ( *convertor )( header.sh_offset );
++		}
++
++		save_header( stream, header_offset );
++		if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL &&
++			 get_size() != 0 && data != 0 ) {
++			save_data( stream, data_offset );
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	void save_header( std::ostream& stream, std::streampos header_offset ) const
++	{
++		stream.seekp( header_offset );
++		stream.write( reinterpret_cast<const char*>( &header ),
++					  sizeof( header ) );
++	}
++
++	//------------------------------------------------------------------------------
++	void save_data( std::ostream& stream, std::streampos data_offset ) const
++	{
++		stream.seekp( data_offset );
++		stream.write( get_data(), get_size() );
++	}
++
++	//------------------------------------------------------------------------------
++	size_t get_stream_size() const { return stream_size; }
++
++	//------------------------------------------------------------------------------
++	void set_stream_size( size_t value ) { stream_size = value; }
++
++	//------------------------------------------------------------------------------
++  private:
++	T                          header;
++	Elf_Half                   index;
++	std::string                name;
++	char*                      data;
++	Elf_Word                   data_size;
++	const endianess_convertor* convertor;
++	bool                       is_address_set;
++	size_t                     stream_size;
++};
++
++} // namespace ELFIO
++
++#endif // ELFIO_SECTION_HPP
++
++/*** End of inlined file: elfio_section.hpp ***/
++
++
++/*** Start of inlined file: elfio_segment.hpp ***/
++#ifndef ELFIO_SEGMENT_HPP
++#define ELFIO_SEGMENT_HPP
++
++#include <iostream>
++#include <vector>
++#include <new>
++
++namespace ELFIO {
++
++class segment
++{
++	friend class elfio;
++
++  public:
++	virtual ~segment(){};
++
++	ELFIO_GET_ACCESS_DECL( Elf_Half, index );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address );
++	ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
++	ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
++	ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
++
++	virtual const char* get_data() const = 0;
++
++	virtual Elf_Half add_section_index( Elf_Half  index,
++										Elf_Xword addr_align )  = 0;
++	virtual Elf_Half get_sections_num() const                   = 0;
++	virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
++	virtual bool     is_offset_initialized() const              = 0;
++
++  protected:
++	ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
++	ELFIO_SET_ACCESS_DECL( Elf_Half, index );
++
++	virtual const std::vector<Elf_Half>& get_sections() const               = 0;
++	virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
++	virtual void save( std::ostream&  stream,
++					   std::streampos header_offset,
++					   std::streampos data_offset )                         = 0;
++};
++
++//------------------------------------------------------------------------------
++template <class T> class segment_impl : public segment
++{
++  public:
++	//------------------------------------------------------------------------------
++	segment_impl( endianess_convertor* convertor_ )
++		: stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ )
++	{
++		is_offset_set = false;
++		std::fill_n( reinterpret_cast<char*>( &ph ), sizeof( ph ), '\0' );
++	}
++
++	//------------------------------------------------------------------------------
++	virtual ~segment_impl() { delete[] data; }
++
++	//------------------------------------------------------------------------------
++	// Section info functions
++	ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type );
++	ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align );
++	ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr );
++	ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz );
++	ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz );
++	ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset );
++	size_t stream_size;
++
++	//------------------------------------------------------------------------------
++	size_t get_stream_size() const { return stream_size; }
++
++	//------------------------------------------------------------------------------
++	void set_stream_size( size_t value ) { stream_size = value; }
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_index() const { return index; }
++
++	//------------------------------------------------------------------------------
++	const char* get_data() const { return data; }
++
++	//------------------------------------------------------------------------------
++	Elf_Half add_section_index( Elf_Half sec_index, Elf_Xword addr_align )
++	{
++		sections.push_back( sec_index );
++		if ( addr_align > get_align() ) {
++			set_align( addr_align );
++		}
++
++		return (Elf_Half)sections.size();
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_sections_num() const { return (Elf_Half)sections.size(); }
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_section_index_at( Elf_Half num ) const
++	{
++		if ( num < sections.size() ) {
++			return sections[num];
++		}
++
++		return Elf_Half( -1 );
++	}
++
++	//------------------------------------------------------------------------------
++  protected:
++	//------------------------------------------------------------------------------
++
++	//------------------------------------------------------------------------------
++	void set_offset( Elf64_Off value )
++	{
++		ph.p_offset   = value;
++		ph.p_offset   = ( *convertor )( ph.p_offset );
++		is_offset_set = true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool is_offset_initialized() const { return is_offset_set; }
++
++	//------------------------------------------------------------------------------
++	const std::vector<Elf_Half>& get_sections() const { return sections; }
++
++	//------------------------------------------------------------------------------
++	void set_index( Elf_Half value ) { index = value; }
++
++	//------------------------------------------------------------------------------
++	void load( std::istream& stream, std::streampos header_offset )
++	{
++
++		stream.seekg( 0, stream.end );
++		set_stream_size( stream.tellg() );
++
++		stream.seekg( header_offset );
++		stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
++		is_offset_set = true;
++
++		if ( PT_NULL != get_type() && 0 != get_file_size() ) {
++			stream.seekg( ( *convertor )( ph.p_offset ) );
++			Elf_Xword size = get_file_size();
++
++			if ( size > get_stream_size() ) {
++				data = 0;
++			}
++			else {
++				data = new (std::nothrow) char[size + 1];
++
++				if ( 0 != data ) {
++					stream.read( data, size );
++					data[size] = 0;
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void save( std::ostream&  stream,
++			   std::streampos header_offset,
++			   std::streampos data_offset )
++	{
++		ph.p_offset = data_offset;
++		ph.p_offset = ( *convertor )( ph.p_offset );
++		stream.seekp( header_offset );
++		stream.write( reinterpret_cast<const char*>( &ph ), sizeof( ph ) );
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	T                     ph;
++	Elf_Half              index;
++	char*                 data;
++	std::vector<Elf_Half> sections;
++	endianess_convertor*  convertor;
++	bool                  is_offset_set;
++};
++
++} // namespace ELFIO
++
++#endif // ELFIO_SEGMENT_HPP
++
++/*** End of inlined file: elfio_segment.hpp ***/
++
++
++/*** Start of inlined file: elfio_strings.hpp ***/
++#ifndef ELFIO_STRINGS_HPP
++#define ELFIO_STRINGS_HPP
++
++#include <cstdlib>
++#include <cstring>
++#include <string>
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++template <class S> class string_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	string_section_accessor_template( S* section_ ) : string_section( section_ )
++	{
++	}
++
++	//------------------------------------------------------------------------------
++	const char* get_string( Elf_Word index ) const
++	{
++		if ( string_section ) {
++			if ( index < string_section->get_size() ) {
++				const char* data = string_section->get_data();
++				if ( 0 != data ) {
++					return data + index;
++				}
++			}
++		}
++
++		return 0;
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_string( const char* str )
++	{
++		Elf_Word current_position = 0;
++
++		if ( string_section ) {
++			// Strings are addeded to the end of the current section data
++			current_position = (Elf_Word)string_section->get_size();
++
++			if ( current_position == 0 ) {
++				char empty_string = '\0';
++				string_section->append_data( &empty_string, 1 );
++				current_position++;
++			}
++			string_section->append_data( str,
++										 (Elf_Word)std::strlen( str ) + 1 );
++		}
++
++		return current_position;
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_string( const std::string& str )
++	{
++		return add_string( str.c_str() );
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	S* string_section;
++};
++
++using string_section_accessor = string_section_accessor_template<section>;
++using const_string_section_accessor =
++	string_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_STRINGS_HPP
++
++/*** End of inlined file: elfio_strings.hpp ***/
++
++#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \
++	TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; }
++
++#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME )     \
++	TYPE get_##FNAME() const                           \
++	{                                                  \
++		return header ? ( header->get_##FNAME() ) : 0; \
++	}                                                  \
++	void set_##FNAME( TYPE val )                       \
++	{                                                  \
++		if ( header ) {                                \
++			header->set_##FNAME( val );                \
++		}                                              \
++	}
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++class elfio
++{
++  public:
++	//------------------------------------------------------------------------------
++	elfio() : sections( this ), segments( this )
++	{
++		header           = 0;
++		current_file_pos = 0;
++		create( ELFCLASS32, ELFDATA2LSB );
++	}
++
++	//------------------------------------------------------------------------------
++	~elfio() { clean(); }
++
++	//------------------------------------------------------------------------------
++	void create( unsigned char file_class, unsigned char encoding )
++	{
++		clean();
++		convertor.setup( encoding );
++		header = create_header( file_class, encoding );
++		create_mandatory_sections();
++	}
++
++	//------------------------------------------------------------------------------
++	bool load( const std::string& file_name )
++	{
++		std::ifstream stream;
++		stream.open( file_name.c_str(), std::ios::in | std::ios::binary );
++		if ( !stream ) {
++			return false;
++		}
++
++		return load( stream );
++	}
++
++	//------------------------------------------------------------------------------
++	bool load( std::istream& stream )
++	{
++		clean();
++
++		unsigned char e_ident[EI_NIDENT];
++		// Read ELF file signature
++		stream.read( reinterpret_cast<char*>( &e_ident ), sizeof( e_ident ) );
++
++		// Is it ELF file?
++		if ( stream.gcount() != sizeof( e_ident ) ||
++			 e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
++			 e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) {
++			return false;
++		}
++
++		if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) &&
++			 ( e_ident[EI_CLASS] != ELFCLASS32 ) ) {
++			return false;
++		}
++
++		convertor.setup( e_ident[EI_DATA] );
++		header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] );
++		if ( 0 == header ) {
++			return false;
++		}
++		if ( !header->load( stream ) ) {
++			return false;
++		}
++
++		load_sections( stream );
++		bool is_still_good = load_segments( stream );
++		return is_still_good;
++	}
++
++	//------------------------------------------------------------------------------
++	bool save( const std::string& file_name )
++	{
++		std::ofstream stream;
++		stream.open( file_name.c_str(), std::ios::out | std::ios::binary );
++		if ( !stream ) {
++			return false;
++		}
++
++		return save( stream );
++	}
++
++	//------------------------------------------------------------------------------
++	bool save( std::ostream& stream )
++	{
++		if ( !stream || !header ) {
++			return false;
++		}
++
++		bool is_still_good = true;
++		// Define layout specific header fields
++		// The position of the segment table is fixed after the header.
++		// The position of the section table is variable and needs to be fixed
++		// before saving.
++		header->set_segments_num( segments.size() );
++		header->set_segments_offset( segments.size() ? header->get_header_size()
++													 : 0 );
++		header->set_sections_num( sections.size() );
++		header->set_sections_offset( 0 );
++
++		// Layout the first section right after the segment table
++		current_file_pos = header->get_header_size() +
++						   header->get_segment_entry_size() *
++							   (Elf_Xword)header->get_segments_num();
++
++		calc_segment_alignment();
++
++		is_still_good = layout_segments_and_their_sections();
++		is_still_good = is_still_good && layout_sections_without_segments();
++		is_still_good = is_still_good && layout_section_table();
++
++		is_still_good = is_still_good && save_header( stream );
++		is_still_good = is_still_good && save_sections( stream );
++		is_still_good = is_still_good && save_segments( stream );
++
++		return is_still_good;
++	}
++
++	//------------------------------------------------------------------------------
++	// ELF header access functions
++	ELFIO_HEADER_ACCESS_GET( unsigned char, class );
++	ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version );
++	ELFIO_HEADER_ACCESS_GET( unsigned char, encoding );
++	ELFIO_HEADER_ACCESS_GET( Elf_Word, version );
++	ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size );
++	ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size );
++	ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size );
++
++	ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi );
++	ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset );
++	ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index );
++
++	//------------------------------------------------------------------------------
++	const endianess_convertor& get_convertor() const { return convertor; }
++
++	//------------------------------------------------------------------------------
++	Elf_Xword get_default_entry_size( Elf_Word section_type ) const
++	{
++		switch ( section_type ) {
++		case SHT_RELA:
++			if ( header->get_class() == ELFCLASS64 ) {
++				return sizeof( Elf64_Rela );
++			}
++			else {
++				return sizeof( Elf32_Rela );
++			}
++		case SHT_REL:
++			if ( header->get_class() == ELFCLASS64 ) {
++				return sizeof( Elf64_Rel );
++			}
++			else {
++				return sizeof( Elf32_Rel );
++			}
++		case SHT_SYMTAB:
++			if ( header->get_class() == ELFCLASS64 ) {
++				return sizeof( Elf64_Sym );
++			}
++			else {
++				return sizeof( Elf32_Sym );
++			}
++		case SHT_DYNAMIC:
++			if ( header->get_class() == ELFCLASS64 ) {
++				return sizeof( Elf64_Dyn );
++			}
++			else {
++				return sizeof( Elf32_Dyn );
++			}
++		default:
++			return 0;
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	bool is_offset_in_section( Elf64_Off offset, const section* sec ) const
++	{
++		return ( offset >= sec->get_offset() ) &&
++			   ( offset < ( sec->get_offset() + sec->get_size() ) );
++	}
++
++	//------------------------------------------------------------------------------
++  public:
++	//! returns an empty string if no problems are detected,
++	//! or a string containing an error message if problems are found
++	std::string validate() const
++	{
++
++		// check for overlapping sections in the file
++		for ( int i = 0; i < sections.size(); ++i ) {
++			for ( int j = i + 1; j < sections.size(); ++j ) {
++				const section* a = sections[i];
++				const section* b = sections[j];
++				if ( !( a->get_type() & SHT_NOBITS ) &&
++					 !( b->get_type() & SHT_NOBITS ) && ( a->get_size() > 0 ) &&
++					 ( b->get_size() > 0 ) && ( a->get_offset() > 0 ) &&
++					 ( b->get_offset() > 0 ) ) {
++					if ( is_offset_in_section( a->get_offset(), b ) ||
++						 is_offset_in_section(
++							 a->get_offset() + a->get_size() - 1, b ) ||
++						 is_offset_in_section( b->get_offset(), a ) ||
++						 is_offset_in_section(
++							 b->get_offset() + b->get_size() - 1, a ) ) {
++						return "Sections " + a->get_name() + " and " +
++							   b->get_name() + " overlap in file";
++					}
++				}
++			}
++		}
++
++		// more checks to be added here...
++
++		return "";
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	void clean()
++	{
++		delete header;
++		header = 0;
++
++		std::vector<section*>::const_iterator it;
++		for ( it = sections_.begin(); it != sections_.end(); ++it ) {
++			delete *it;
++		}
++		sections_.clear();
++
++		std::vector<segment*>::const_iterator it1;
++		for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) {
++			delete *it1;
++		}
++		segments_.clear();
++	}
++
++	//------------------------------------------------------------------------------
++	elf_header* create_header( unsigned char file_class,
++							   unsigned char encoding )
++	{
++		elf_header* new_header = 0;
++
++		if ( file_class == ELFCLASS64 ) {
++			new_header =
++				new elf_header_impl<Elf64_Ehdr>( &convertor, encoding );
++		}
++		else if ( file_class == ELFCLASS32 ) {
++			new_header =
++				new elf_header_impl<Elf32_Ehdr>( &convertor, encoding );
++		}
++		else {
++			return 0;
++		}
++
++		return new_header;
++	}
++
++	//------------------------------------------------------------------------------
++	section* create_section()
++	{
++		section*      new_section;
++		unsigned char file_class = get_class();
++
++		if ( file_class == ELFCLASS64 ) {
++			new_section = new section_impl<Elf64_Shdr>( &convertor );
++		}
++		else if ( file_class == ELFCLASS32 ) {
++			new_section = new section_impl<Elf32_Shdr>( &convertor );
++		}
++		else {
++			return 0;
++		}
++
++		new_section->set_index( (Elf_Half)sections_.size() );
++		sections_.push_back( new_section );
++
++		return new_section;
++	}
++
++	//------------------------------------------------------------------------------
++	segment* create_segment()
++	{
++		segment*      new_segment;
++		unsigned char file_class = header->get_class();
++
++		if ( file_class == ELFCLASS64 ) {
++			new_segment = new segment_impl<Elf64_Phdr>( &convertor );
++		}
++		else if ( file_class == ELFCLASS32 ) {
++			new_segment = new segment_impl<Elf32_Phdr>( &convertor );
++		}
++		else {
++			return 0;
++		}
++
++		new_segment->set_index( (Elf_Half)segments_.size() );
++		segments_.push_back( new_segment );
++
++		return new_segment;
++	}
++
++	//------------------------------------------------------------------------------
++	void create_mandatory_sections()
++	{
++		// Create null section without calling to 'add_section' as no string
++		// section containing section names exists yet
++		section* sec0 = create_section();
++		sec0->set_index( 0 );
++		sec0->set_name( "" );
++		sec0->set_name_string_offset( 0 );
++
++		set_section_name_str_index( 1 );
++		section* shstrtab = sections.add( ".shstrtab" );
++		shstrtab->set_type( SHT_STRTAB );
++		shstrtab->set_addr_align( 1 );
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Half load_sections( std::istream& stream )
++	{
++		Elf_Half  entry_size = header->get_section_entry_size();
++		Elf_Half  num        = header->get_sections_num();
++		Elf64_Off offset     = header->get_sections_offset();
++
++		for ( Elf_Half i = 0; i < num; ++i ) {
++			section* sec = create_section();
++			sec->load( stream, (std::streamoff)offset +
++								   (std::streampos)i * entry_size );
++			sec->set_index( i );
++			// To mark that the section is not permitted to reassign address
++			// during layout calculation
++			sec->set_address( sec->get_address() );
++		}
++
++		Elf_Half shstrndx = get_section_name_str_index();
++
++		if ( SHN_UNDEF != shstrndx ) {
++			string_section_accessor str_reader( sections[shstrndx] );
++			for ( Elf_Half i = 0; i < num; ++i ) {
++				Elf_Word section_offset = sections[i]->get_name_string_offset();
++				const char* p = str_reader.get_string( section_offset );
++				if ( p != 0 ) {
++					sections[i]->set_name( p );
++				}
++			}
++		}
++
++		return num;
++	}
++
++	//------------------------------------------------------------------------------
++	//! Checks whether the addresses of the section entirely fall within the given segment.
++	//! It doesn't matter if the addresses are memory addresses, or file offsets,
++	//!  they just need to be in the same address space
++	bool is_sect_in_seg( Elf64_Off sect_begin,
++						 Elf_Xword sect_size,
++						 Elf64_Off seg_begin,
++						 Elf64_Off seg_end )
++	{
++		return ( seg_begin <= sect_begin ) &&
++			   ( sect_begin + sect_size <= seg_end ) &&
++			   ( sect_begin <
++				 seg_end ); // this is important criteria when sect_size == 0
++		// Example:  seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11)
++		//           sect_begin=12, sect_size=0  -> shall return false!
++	}
++
++	//------------------------------------------------------------------------------
++	bool load_segments( std::istream& stream )
++	{
++		Elf_Half  entry_size = header->get_segment_entry_size();
++		Elf_Half  num        = header->get_segments_num();
++		Elf64_Off offset     = header->get_segments_offset();
++
++		for ( Elf_Half i = 0; i < num; ++i ) {
++			segment*      seg;
++			unsigned char file_class = header->get_class();
++
++			if ( file_class == ELFCLASS64 ) {
++				seg = new segment_impl<Elf64_Phdr>( &convertor );
++			}
++			else if ( file_class == ELFCLASS32 ) {
++				seg = new segment_impl<Elf32_Phdr>( &convertor );
++			}
++			else {
++				return false;
++			}
++
++			seg->load( stream, (std::streamoff)offset +
++								   (std::streampos)i * entry_size );
++			seg->set_index( i );
++
++			// Add sections to the segments (similar to readelfs algorithm)
++			Elf64_Off segBaseOffset = seg->get_offset();
++			Elf64_Off segEndOffset  = segBaseOffset + seg->get_file_size();
++			Elf64_Off segVBaseAddr  = seg->get_virtual_address();
++			Elf64_Off segVEndAddr   = segVBaseAddr + seg->get_memory_size();
++			for ( Elf_Half j = 0; j < sections.size(); ++j ) {
++				const section* psec = sections[j];
++
++				// SHF_ALLOC sections are matched based on the virtual address
++				// otherwise the file offset is matched
++				if ( ( psec->get_flags() & SHF_ALLOC )
++						 ? is_sect_in_seg( psec->get_address(),
++										   psec->get_size(), segVBaseAddr,
++										   segVEndAddr )
++						 : is_sect_in_seg( psec->get_offset(), psec->get_size(),
++										   segBaseOffset, segEndOffset ) ) {
++					// Alignment of segment shall not be updated, to preserve original value
++					// It will be re-calculated on saving.
++					seg->add_section_index( psec->get_index(), 0 );
++				}
++			}
++
++			// Add section into the segments' container
++			segments_.push_back( seg );
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool save_header( std::ostream& stream ) { return header->save( stream ); }
++
++	//------------------------------------------------------------------------------
++	bool save_sections( std::ostream& stream )
++	{
++		for ( unsigned int i = 0; i < sections_.size(); ++i ) {
++			section* sec = sections_.at( i );
++
++			std::streampos headerPosition =
++				(std::streamoff)header->get_sections_offset() +
++				(std::streampos)header->get_section_entry_size() *
++					sec->get_index();
++
++			sec->save( stream, headerPosition, sec->get_offset() );
++		}
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool save_segments( std::ostream& stream )
++	{
++		for ( unsigned int i = 0; i < segments_.size(); ++i ) {
++			segment* seg = segments_.at( i );
++
++			std::streampos headerPosition =
++				header->get_segments_offset() +
++				(std::streampos)header->get_segment_entry_size() *
++					seg->get_index();
++
++			seg->save( stream, headerPosition, seg->get_offset() );
++		}
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool is_section_without_segment( unsigned int section_index )
++	{
++		bool found = false;
++
++		for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) {
++			for ( unsigned int k = 0;
++				  !found && ( k < segments[j]->get_sections_num() ); ++k ) {
++				found = segments[j]->get_section_index_at( k ) == section_index;
++			}
++		}
++
++		return !found;
++	}
++
++	//------------------------------------------------------------------------------
++	bool is_subsequence_of( segment* seg1, segment* seg2 )
++	{
++		// Return 'true' if sections of seg1 are a subset of sections in seg2
++		const std::vector<Elf_Half>& sections1 = seg1->get_sections();
++		const std::vector<Elf_Half>& sections2 = seg2->get_sections();
++
++		bool found = false;
++		if ( sections1.size() < sections2.size() ) {
++			found = std::includes( sections2.begin(), sections2.end(),
++								   sections1.begin(), sections1.end() );
++		}
++
++		return found;
++	}
++
++	//------------------------------------------------------------------------------
++	std::vector<segment*> get_ordered_segments()
++	{
++		std::vector<segment*> res;
++		std::deque<segment*>  worklist;
++
++		res.reserve( segments.size() );
++		std::copy( segments_.begin(), segments_.end(),
++				   std::back_inserter( worklist ) );
++
++		// Bring the segments which start at address 0 to the front
++		size_t nextSlot = 0;
++		for ( size_t i = 0; i < worklist.size(); ++i ) {
++			if ( i != nextSlot && worklist[i]->is_offset_initialized() &&
++				 worklist[i]->get_offset() == 0 ) {
++				if ( worklist[nextSlot]->get_offset() == 0 ) {
++					++nextSlot;
++				}
++				std::swap( worklist[i], worklist[nextSlot] );
++				++nextSlot;
++			}
++		}
++
++		while ( !worklist.empty() ) {
++			segment* seg = worklist.front();
++			worklist.pop_front();
++
++			size_t i = 0;
++			for ( ; i < worklist.size(); ++i ) {
++				if ( is_subsequence_of( seg, worklist[i] ) ) {
++					break;
++				}
++			}
++
++			if ( i < worklist.size() )
++				worklist.push_back( seg );
++			else
++				res.push_back( seg );
++		}
++
++		return res;
++	}
++
++	//------------------------------------------------------------------------------
++	bool layout_sections_without_segments()
++	{
++		for ( unsigned int i = 0; i < sections_.size(); ++i ) {
++			if ( is_section_without_segment( i ) ) {
++				section* sec = sections_[i];
++
++				Elf_Xword section_align = sec->get_addr_align();
++				if ( section_align > 1 &&
++					 current_file_pos % section_align != 0 ) {
++					current_file_pos +=
++						section_align - current_file_pos % section_align;
++				}
++
++				if ( 0 != sec->get_index() )
++					sec->set_offset( current_file_pos );
++
++				if ( SHT_NOBITS != sec->get_type() &&
++					 SHT_NULL != sec->get_type() ) {
++					current_file_pos += sec->get_size();
++				}
++			}
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	void calc_segment_alignment()
++	{
++		for ( std::vector<segment*>::iterator s = segments_.begin();
++			  s != segments_.end(); ++s ) {
++			segment* seg = *s;
++			for ( int i = 0; i < seg->get_sections_num(); ++i ) {
++				section* sect = sections_[seg->get_section_index_at( i )];
++				if ( sect->get_addr_align() > seg->get_align() ) {
++					seg->set_align( sect->get_addr_align() );
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	bool layout_segments_and_their_sections()
++	{
++		std::vector<segment*> worklist;
++		std::vector<bool>     section_generated( sections.size(), false );
++
++		// Get segments in a order in where segments which contain a
++		// sub sequence of other segments are located at the end
++		worklist = get_ordered_segments();
++
++		for ( unsigned int i = 0; i < worklist.size(); ++i ) {
++			Elf_Xword segment_memory   = 0;
++			Elf_Xword segment_filesize = 0;
++			Elf_Xword seg_start_pos    = current_file_pos;
++			segment*  seg              = worklist[i];
++
++			// Special case: PHDR segment
++			// This segment contains the program headers but no sections
++			if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) {
++				seg_start_pos  = header->get_segments_offset();
++				segment_memory = segment_filesize =
++					header->get_segment_entry_size() *
++					(Elf_Xword)header->get_segments_num();
++			}
++			// Special case:
++			else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) {
++				seg_start_pos = 0;
++				if ( seg->get_sections_num() ) {
++					segment_memory = segment_filesize = current_file_pos;
++				}
++			}
++			// New segments with not generated sections
++			// have to be aligned
++			else if ( seg->get_sections_num() &&
++					  !section_generated[seg->get_section_index_at( 0 )] ) {
++				Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1;
++				Elf64_Off cur_page_alignment = current_file_pos % align;
++				Elf64_Off req_page_alignment =
++					seg->get_virtual_address() % align;
++				Elf64_Off error = req_page_alignment - cur_page_alignment;
++
++				current_file_pos += ( seg->get_align() + error ) % align;
++				seg_start_pos = current_file_pos;
++			}
++			else if ( seg->get_sections_num() ) {
++				seg_start_pos =
++					sections[seg->get_section_index_at( 0 )]->get_offset();
++			}
++
++			// Write segment's data
++			for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) {
++				Elf_Half index = seg->get_section_index_at( j );
++
++				section* sec = sections[index];
++
++				// The NULL section is always generated
++				if ( SHT_NULL == sec->get_type() ) {
++					section_generated[index] = true;
++					continue;
++				}
++
++				Elf_Xword secAlign = 0;
++				// Fix up the alignment
++				if ( !section_generated[index] &&
++					 sec->is_address_initialized() &&
++					 SHT_NOBITS != sec->get_type() &&
++					 SHT_NULL != sec->get_type() && 0 != sec->get_size() ) {
++					// Align the sections based on the virtual addresses
++					// when possible (this is what matters for execution)
++					Elf64_Off req_offset =
++						sec->get_address() - seg->get_virtual_address();
++					Elf64_Off cur_offset = current_file_pos - seg_start_pos;
++					if ( req_offset < cur_offset ) {
++						// something has gone awfully wrong, abort!
++						// secAlign would turn out negative, seeking backwards and overwriting previous data
++						return false;
++					}
++					secAlign = req_offset - cur_offset;
++				}
++				else if ( !section_generated[index] &&
++						  !sec->is_address_initialized() ) {
++					// If no address has been specified then only the section
++					// alignment constraint has to be matched
++					Elf_Xword align = sec->get_addr_align();
++					if ( align == 0 ) {
++						align = 1;
++					}
++					Elf64_Off error = current_file_pos % align;
++					secAlign        = ( align - error ) % align;
++				}
++				else if ( section_generated[index] ) {
++					// Alignment for already generated sections
++					secAlign =
++						sec->get_offset() - seg_start_pos - segment_filesize;
++				}
++
++				// Determine the segment file and memory sizes
++				// Special case .tbss section (NOBITS) in non TLS segment
++				if ( ( sec->get_flags() & SHF_ALLOC ) &&
++					 !( ( sec->get_flags() & SHF_TLS ) &&
++						( seg->get_type() != PT_TLS ) &&
++						( SHT_NOBITS == sec->get_type() ) ) )
++					segment_memory += sec->get_size() + secAlign;
++
++				if ( SHT_NOBITS != sec->get_type() )
++					segment_filesize += sec->get_size() + secAlign;
++
++				// Nothing to be done when generating nested segments
++				if ( section_generated[index] ) {
++					continue;
++				}
++
++				current_file_pos += secAlign;
++
++				// Set the section addresses when missing
++				if ( !sec->is_address_initialized() )
++					sec->set_address( seg->get_virtual_address() +
++									  current_file_pos - seg_start_pos );
++
++				if ( 0 != sec->get_index() )
++					sec->set_offset( current_file_pos );
++
++				if ( SHT_NOBITS != sec->get_type() )
++					current_file_pos += sec->get_size();
++
++				section_generated[index] = true;
++			}
++
++			seg->set_file_size( segment_filesize );
++
++			// If we already have a memory size from loading an elf file (value > 0),
++			// it must not shrink!
++			// Memory size may be bigger than file size and it is the loader's job to do something
++			// with the surplus bytes in memory, like initializing them with a defined value.
++			if ( seg->get_memory_size() < segment_memory ) {
++				seg->set_memory_size( segment_memory );
++			}
++
++			seg->set_offset( seg_start_pos );
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool layout_section_table()
++	{
++		// Simply place the section table at the end for now
++		Elf64_Off alignmentError = current_file_pos % 4;
++		current_file_pos += ( 4 - alignmentError ) % 4;
++		header->set_sections_offset( current_file_pos );
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++  public:
++	friend class Sections;
++	class Sections
++	{
++	  public:
++		//------------------------------------------------------------------------------
++		Sections( elfio* parent_ ) : parent( parent_ ) {}
++
++		//------------------------------------------------------------------------------
++		Elf_Half size() const { return (Elf_Half)parent->sections_.size(); }
++
++		//------------------------------------------------------------------------------
++		section* operator[]( unsigned int index ) const
++		{
++			section* sec = 0;
++
++			if ( index < parent->sections_.size() ) {
++				sec = parent->sections_[index];
++			}
++
++			return sec;
++		}
++
++		//------------------------------------------------------------------------------
++		section* operator[]( const std::string& name ) const
++		{
++			section* sec = 0;
++
++			std::vector<section*>::const_iterator it;
++			for ( it = parent->sections_.begin(); it != parent->sections_.end();
++				  ++it ) {
++				if ( ( *it )->get_name() == name ) {
++					sec = *it;
++					break;
++				}
++			}
++
++			return sec;
++		}
++
++		//------------------------------------------------------------------------------
++		section* add( const std::string& name )
++		{
++			section* new_section = parent->create_section();
++			new_section->set_name( name );
++
++			Elf_Half str_index = parent->get_section_name_str_index();
++			section* string_table( parent->sections_[str_index] );
++			string_section_accessor str_writer( string_table );
++			Elf_Word                pos = str_writer.add_string( name );
++			new_section->set_name_string_offset( pos );
++
++			return new_section;
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<section*>::iterator begin()
++		{
++			return parent->sections_.begin();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<section*>::iterator end()
++		{
++			return parent->sections_.end();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<section*>::const_iterator begin() const
++		{
++			return parent->sections_.cbegin();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<section*>::const_iterator end() const
++		{
++			return parent->sections_.cend();
++		}
++
++		//------------------------------------------------------------------------------
++	  private:
++		elfio* parent;
++	} sections;
++
++	//------------------------------------------------------------------------------
++  public:
++	friend class Segments;
++	class Segments
++	{
++	  public:
++		//------------------------------------------------------------------------------
++		Segments( elfio* parent_ ) : parent( parent_ ) {}
++
++		//------------------------------------------------------------------------------
++		Elf_Half size() const { return (Elf_Half)parent->segments_.size(); }
++
++		//------------------------------------------------------------------------------
++		segment* operator[]( unsigned int index ) const
++		{
++			return parent->segments_[index];
++		}
++
++		//------------------------------------------------------------------------------
++		segment* add() { return parent->create_segment(); }
++
++		//------------------------------------------------------------------------------
++		std::vector<segment*>::iterator begin()
++		{
++			return parent->segments_.begin();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<segment*>::iterator end()
++		{
++			return parent->segments_.end();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<segment*>::const_iterator begin() const
++		{
++			return parent->segments_.cbegin();
++		}
++
++		//------------------------------------------------------------------------------
++		std::vector<segment*>::const_iterator end() const
++		{
++			return parent->segments_.cend();
++		}
++
++		//------------------------------------------------------------------------------
++	  private:
++		elfio* parent;
++	} segments;
++
++	//------------------------------------------------------------------------------
++  private:
++	elf_header*           header;
++	std::vector<section*> sections_;
++	std::vector<segment*> segments_;
++	endianess_convertor   convertor;
++
++	Elf_Xword current_file_pos;
++};
++
++} // namespace ELFIO
++
++
++/*** Start of inlined file: elfio_symbols.hpp ***/
++#ifndef ELFIO_SYMBOLS_HPP
++#define ELFIO_SYMBOLS_HPP
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++template <class S> class symbol_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	symbol_section_accessor_template( const elfio& elf_file_,
++									  S*           symbol_section_ )
++		: elf_file( elf_file_ ), symbol_section( symbol_section_ )
++	{
++		find_hash_section();
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Xword get_symbols_num() const
++	{
++		Elf_Xword nRet = 0;
++		if ( 0 != symbol_section->get_entry_size() ) {
++			nRet =
++				symbol_section->get_size() / symbol_section->get_entry_size();
++		}
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_symbol( Elf_Xword      index,
++					 std::string&   name,
++					 Elf64_Addr&    value,
++					 Elf_Xword&     size,
++					 unsigned char& bind,
++					 unsigned char& type,
++					 Elf_Half&      section_index,
++					 unsigned char& other ) const
++	{
++		bool ret = false;
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			ret = generic_get_symbol<Elf32_Sym>( index, name, value, size, bind,
++												 type, section_index, other );
++		}
++		else {
++			ret = generic_get_symbol<Elf64_Sym>( index, name, value, size, bind,
++												 type, section_index, other );
++		}
++
++		return ret;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_symbol( const std::string& name,
++					 Elf64_Addr&        value,
++					 Elf_Xword&         size,
++					 unsigned char&     bind,
++					 unsigned char&     type,
++					 Elf_Half&          section_index,
++					 unsigned char&     other ) const
++	{
++		bool ret = false;
++
++		if ( 0 != get_hash_table_index() ) {
++			Elf_Word    nbucket = *(const Elf_Word*)hash_section->get_data();
++			Elf_Word    nchain  = *(const Elf_Word*)( hash_section->get_data() +
++												  sizeof( Elf_Word ) );
++			Elf_Word    val = elf_hash( (const unsigned char*)name.c_str() );
++			Elf_Word    y   = *(const Elf_Word*)( hash_section->get_data() +
++											 ( 2 + val % nbucket ) *
++												 sizeof( Elf_Word ) );
++			std::string str;
++			get_symbol( y, str, value, size, bind, type, section_index, other );
++			while ( str != name && STN_UNDEF != y && y < nchain ) {
++				y = *(const Elf_Word*)( hash_section->get_data() +
++										( 2 + nbucket + y ) *
++											sizeof( Elf_Word ) );
++				get_symbol( y, str, value, size, bind, type, section_index,
++							other );
++			}
++			if ( str == name ) {
++				ret = true;
++			}
++		}
++		else {
++			for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) {
++				std::string symbol_name;
++				if ( get_symbol( i, symbol_name, value, size, bind, type,
++								 section_index, other ) ) {
++					if ( symbol_name == name ) {
++						ret = true;
++					}
++				}
++			}
++		}
++
++		return ret;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_symbol( const Elf64_Addr& value,
++					 std::string&      name,
++					 Elf_Xword&        size,
++					 unsigned char&    bind,
++					 unsigned char&    type,
++					 Elf_Half&         section_index,
++					 unsigned char&    other ) const
++	{
++
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		Elf_Xword  idx   = 0;
++		bool       match = false;
++		Elf64_Addr v     = 0;
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			match = generic_search_symbols<Elf32_Sym>(
++				[&]( const Elf32_Sym* sym ) {
++					return convertor( sym->st_value ) == value;
++				},
++				idx );
++		}
++		else {
++			match = generic_search_symbols<Elf64_Sym>(
++				[&]( const Elf64_Sym* sym ) {
++					return convertor( sym->st_value ) == value;
++				},
++				idx );
++		}
++
++		if ( match ) {
++			return get_symbol( idx, name, v, size, bind, type, section_index,
++							   other );
++		}
++
++		return false;
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_symbol( Elf_Word      name,
++						 Elf64_Addr    value,
++						 Elf_Xword     size,
++						 unsigned char info,
++						 unsigned char other,
++						 Elf_Half      shndx )
++	{
++		Elf_Word nRet;
++
++		if ( symbol_section->get_size() == 0 ) {
++			if ( elf_file.get_class() == ELFCLASS32 ) {
++				nRet = generic_add_symbol<Elf32_Sym>( 0, 0, 0, 0, 0, 0 );
++			}
++			else {
++				nRet = generic_add_symbol<Elf64_Sym>( 0, 0, 0, 0, 0, 0 );
++			}
++		}
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			nRet = generic_add_symbol<Elf32_Sym>( name, value, size, info,
++												  other, shndx );
++		}
++		else {
++			nRet = generic_add_symbol<Elf64_Sym>( name, value, size, info,
++												  other, shndx );
++		}
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_symbol( Elf_Word      name,
++						 Elf64_Addr    value,
++						 Elf_Xword     size,
++						 unsigned char bind,
++						 unsigned char type,
++						 unsigned char other,
++						 Elf_Half      shndx )
++	{
++		return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other,
++						   shndx );
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_symbol( string_section_accessor& pStrWriter,
++						 const char*              str,
++						 Elf64_Addr               value,
++						 Elf_Xword                size,
++						 unsigned char            info,
++						 unsigned char            other,
++						 Elf_Half                 shndx )
++	{
++		Elf_Word index = pStrWriter.add_string( str );
++		return add_symbol( index, value, size, info, other, shndx );
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_symbol( string_section_accessor& pStrWriter,
++						 const char*              str,
++						 Elf64_Addr               value,
++						 Elf_Xword                size,
++						 unsigned char            bind,
++						 unsigned char            type,
++						 unsigned char            other,
++						 Elf_Half                 shndx )
++	{
++		return add_symbol( pStrWriter, str, value, size,
++						   ELF_ST_INFO( bind, type ), other, shndx );
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Xword arrange_local_symbols(
++		std::function<void( Elf_Xword first, Elf_Xword second )> func =
++			nullptr )
++	{
++		int nRet = 0;
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			nRet = generic_arrange_local_symbols<Elf32_Sym>( func );
++		}
++		else {
++			nRet = generic_arrange_local_symbols<Elf64_Sym>( func );
++		}
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	void find_hash_section()
++	{
++		hash_section       = 0;
++		hash_section_index = 0;
++		Elf_Half nSecNo    = elf_file.sections.size();
++		for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) {
++			const section* sec = elf_file.sections[i];
++			if ( sec->get_link() == symbol_section->get_index() ) {
++				hash_section       = sec;
++				hash_section_index = i;
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_string_table_index() const
++	{
++		return (Elf_Half)symbol_section->get_link();
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Half get_hash_table_index() const { return hash_section_index; }
++
++	//------------------------------------------------------------------------------
++	template <class T> const T* generic_get_symbol_ptr( Elf_Xword index ) const
++	{
++		if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
++			const T* pSym = reinterpret_cast<const T*>(
++				symbol_section->get_data() +
++				index * symbol_section->get_entry_size() );
++
++			return pSym;
++		}
++
++		return nullptr;
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	bool generic_search_symbols( std::function<bool( const T* )> match,
++								 Elf_Xword&                      idx ) const
++	{
++		for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) {
++			const T* symPtr = generic_get_symbol_ptr<T>( i );
++
++			if ( symPtr == nullptr )
++				return false;
++
++			if ( match( symPtr ) ) {
++				idx = i;
++				return true;
++			}
++		}
++
++		return false;
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	bool generic_get_symbol( Elf_Xword      index,
++							 std::string&   name,
++							 Elf64_Addr&    value,
++							 Elf_Xword&     size,
++							 unsigned char& bind,
++							 unsigned char& type,
++							 Elf_Half&      section_index,
++							 unsigned char& other ) const
++	{
++		bool ret = false;
++
++		if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) {
++			const T* pSym = reinterpret_cast<const T*>(
++				symbol_section->get_data() +
++				index * symbol_section->get_entry_size() );
++
++			const endianess_convertor& convertor = elf_file.get_convertor();
++
++			section* string_section =
++				elf_file.sections[get_string_table_index()];
++			string_section_accessor str_reader( string_section );
++			const char*             pStr =
++				str_reader.get_string( convertor( pSym->st_name ) );
++			if ( 0 != pStr ) {
++				name = pStr;
++			}
++			value         = convertor( pSym->st_value );
++			size          = convertor( pSym->st_size );
++			bind          = ELF_ST_BIND( pSym->st_info );
++			type          = ELF_ST_TYPE( pSym->st_info );
++			section_index = convertor( pSym->st_shndx );
++			other         = pSym->st_other;
++
++			ret = true;
++		}
++
++		return ret;
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	Elf_Word generic_add_symbol( Elf_Word      name,
++								 Elf64_Addr    value,
++								 Elf_Xword     size,
++								 unsigned char info,
++								 unsigned char other,
++								 Elf_Half      shndx )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T entry;
++		entry.st_name  = convertor( name );
++		entry.st_value = value;
++		entry.st_value = convertor( entry.st_value );
++		entry.st_size  = size;
++		entry.st_size  = convertor( entry.st_size );
++		entry.st_info  = convertor( info );
++		entry.st_other = convertor( other );
++		entry.st_shndx = convertor( shndx );
++
++		symbol_section->append_data( reinterpret_cast<char*>( &entry ),
++									 sizeof( entry ) );
++
++		Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1;
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	Elf_Xword generic_arrange_local_symbols(
++		std::function<void( Elf_Xword first, Elf_Xword second )> func )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++		const Elf_Xword            size      = symbol_section->get_entry_size();
++
++		Elf_Xword first_not_local =
++			1; // Skip the first entry. It is always NOTYPE
++		Elf_Xword current = 0;
++		Elf_Xword count   = get_symbols_num();
++
++		while ( true ) {
++			T* p1 = nullptr;
++			T* p2 = nullptr;
++
++			while ( first_not_local < count ) {
++				p1 = const_cast<T*>(
++					generic_get_symbol_ptr<T>( first_not_local ) );
++				if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL )
++					break;
++				++first_not_local;
++			}
++
++			current = first_not_local + 1;
++			while ( current < count ) {
++				p2 = const_cast<T*>( generic_get_symbol_ptr<T>( current ) );
++				if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL )
++					break;
++				++current;
++			}
++
++			if ( first_not_local < count && current < count ) {
++				if ( func )
++					func( first_not_local, current );
++
++				// Swap the symbols
++				T tmp;
++				std::copy( p1, p1 + 1, &tmp );
++				std::copy( p2, p2 + 1, p1 );
++				std::copy( &tmp, &tmp + 1, p2 );
++			}
++			else {
++				// Update 'info' field of the section
++				symbol_section->set_info( first_not_local );
++				break;
++			}
++		}
++
++		// Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1;
++
++		return first_not_local;
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	const elfio&   elf_file;
++	S*             symbol_section;
++	Elf_Half       hash_section_index;
++	const section* hash_section;
++};
++
++using symbol_section_accessor = symbol_section_accessor_template<section>;
++using const_symbol_section_accessor =
++	symbol_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_SYMBOLS_HPP
++
++/*** End of inlined file: elfio_symbols.hpp ***/
++
++
++/*** Start of inlined file: elfio_note.hpp ***/
++#ifndef ELFIO_NOTE_HPP
++#define ELFIO_NOTE_HPP
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++// There are discrepancies in documentations. SCO documentation
++// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section)
++// requires 8 byte entries alignment for 64-bit ELF file,
++// but Oracle's definition uses the same structure
++// for 32-bit and 64-bit formats.
++// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html)
++//
++// It looks like EM_X86_64 Linux implementation is similar to Oracle's
++// definition. Therefore, the same alignment works for both formats
++//------------------------------------------------------------------------------
++
++//------------------------------------------------------------------------------
++template <class S> class note_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	note_section_accessor_template( const elfio& elf_file_, S* section_ )
++		: elf_file( elf_file_ ), note_section( section_ )
++	{
++		process_section();
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word get_notes_num() const
++	{
++		return (Elf_Word)note_start_positions.size();
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_note( Elf_Word     index,
++				   Elf_Word&    type,
++				   std::string& name,
++				   void*&       desc,
++				   Elf_Word&    descSize ) const
++	{
++		if ( index >= note_section->get_size() ) {
++			return false;
++		}
++
++		const char* pData =
++			note_section->get_data() + note_start_positions[index];
++		int align = sizeof( Elf_Word );
++
++		const endianess_convertor& convertor = elf_file.get_convertor();
++		type            = convertor( *(const Elf_Word*)( pData + 2 * align ) );
++		Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) );
++		descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) );
++
++		Elf_Xword max_name_size =
++			note_section->get_size() - note_start_positions[index];
++		if ( namesz < 1 || namesz > max_name_size ||
++			 (Elf_Xword)namesz + descSize > max_name_size ) {
++			return false;
++		}
++		name.assign( pData + 3 * align, namesz - 1 );
++		if ( 0 == descSize ) {
++			desc = 0;
++		}
++		else {
++			desc =
++				const_cast<char*>( pData + 3 * align +
++								   ( ( namesz + align - 1 ) / align ) * align );
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	void add_note( Elf_Word           type,
++				   const std::string& name,
++				   const void*        desc,
++				   Elf_Word           descSize )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		int         align       = sizeof( Elf_Word );
++		Elf_Word    nameLen     = (Elf_Word)name.size() + 1;
++		Elf_Word    nameLenConv = convertor( nameLen );
++		std::string buffer( reinterpret_cast<char*>( &nameLenConv ), align );
++		Elf_Word    descSizeConv = convertor( descSize );
++
++		buffer.append( reinterpret_cast<char*>( &descSizeConv ), align );
++		type = convertor( type );
++		buffer.append( reinterpret_cast<char*>( &type ), align );
++		buffer.append( name );
++		buffer.append( 1, '\x00' );
++		const char pad[] = { '\0', '\0', '\0', '\0' };
++		if ( nameLen % align != 0 ) {
++			buffer.append( pad, align - nameLen % align );
++		}
++		if ( desc != 0 && descSize != 0 ) {
++			buffer.append( reinterpret_cast<const char*>( desc ), descSize );
++			if ( descSize % align != 0 ) {
++				buffer.append( pad, align - descSize % align );
++			}
++		}
++
++		note_start_positions.push_back( note_section->get_size() );
++		note_section->append_data( buffer );
++	}
++
++  private:
++	//------------------------------------------------------------------------------
++	void process_section()
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++		const char*                data      = note_section->get_data();
++		Elf_Xword                  size      = note_section->get_size();
++		Elf_Xword                  current   = 0;
++
++		note_start_positions.clear();
++
++		// Is it empty?
++		if ( 0 == data || 0 == size ) {
++			return;
++		}
++
++		Elf_Word align = sizeof( Elf_Word );
++		while ( current + (Elf_Xword)3 * align <= size ) {
++			note_start_positions.push_back( current );
++			Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) );
++			Elf_Word descsz = convertor(
++				*(const Elf_Word*)( data + current + sizeof( namesz ) ) );
++
++			current += (Elf_Xword)3 * sizeof( Elf_Word ) +
++					   ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align +
++					   ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align;
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	const elfio&           elf_file;
++	S*                     note_section;
++	std::vector<Elf_Xword> note_start_positions;
++};
++
++using note_section_accessor = note_section_accessor_template<section>;
++using const_note_section_accessor =
++	note_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_NOTE_HPP
++
++/*** End of inlined file: elfio_note.hpp ***/
++
++
++/*** Start of inlined file: elfio_relocation.hpp ***/
++#ifndef ELFIO_RELOCATION_HPP
++#define ELFIO_RELOCATION_HPP
++
++namespace ELFIO {
++
++template <typename T> struct get_sym_and_type;
++template <> struct get_sym_and_type<Elf32_Rel>
++{
++	static int get_r_sym( Elf_Xword info )
++	{
++		return ELF32_R_SYM( (Elf_Word)info );
++	}
++	static int get_r_type( Elf_Xword info )
++	{
++		return ELF32_R_TYPE( (Elf_Word)info );
++	}
++};
++template <> struct get_sym_and_type<Elf32_Rela>
++{
++	static int get_r_sym( Elf_Xword info )
++	{
++		return ELF32_R_SYM( (Elf_Word)info );
++	}
++	static int get_r_type( Elf_Xword info )
++	{
++		return ELF32_R_TYPE( (Elf_Word)info );
++	}
++};
++template <> struct get_sym_and_type<Elf64_Rel>
++{
++	static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
++	static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
++};
++template <> struct get_sym_and_type<Elf64_Rela>
++{
++	static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); }
++	static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); }
++};
++
++//------------------------------------------------------------------------------
++template <class S> class relocation_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	relocation_section_accessor_template( const elfio& elf_file_, S* section_ )
++		: elf_file( elf_file_ ), relocation_section( section_ )
++	{
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Xword get_entries_num() const
++	{
++		Elf_Xword nRet = 0;
++
++		if ( 0 != relocation_section->get_entry_size() ) {
++			nRet = relocation_section->get_size() /
++				   relocation_section->get_entry_size();
++		}
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_entry( Elf_Xword   index,
++					Elf64_Addr& offset,
++					Elf_Word&   symbol,
++					Elf_Word&   type,
++					Elf_Sxword& addend ) const
++	{
++		if ( index >= get_entries_num() ) { // Is index valid
++			return false;
++		}
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			if ( SHT_REL == relocation_section->get_type() ) {
++				generic_get_entry_rel<Elf32_Rel>( index, offset, symbol, type,
++												  addend );
++			}
++			else if ( SHT_RELA == relocation_section->get_type() ) {
++				generic_get_entry_rela<Elf32_Rela>( index, offset, symbol, type,
++													addend );
++			}
++		}
++		else {
++			if ( SHT_REL == relocation_section->get_type() ) {
++				generic_get_entry_rel<Elf64_Rel>( index, offset, symbol, type,
++												  addend );
++			}
++			else if ( SHT_RELA == relocation_section->get_type() ) {
++				generic_get_entry_rela<Elf64_Rela>( index, offset, symbol, type,
++													addend );
++			}
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_entry( Elf_Xword    index,
++					Elf64_Addr&  offset,
++					Elf64_Addr&  symbolValue,
++					std::string& symbolName,
++					Elf_Word&    type,
++					Elf_Sxword&  addend,
++					Elf_Sxword&  calcValue ) const
++	{
++		// Do regular job
++		Elf_Word symbol;
++		bool     ret = get_entry( index, offset, symbol, type, addend );
++
++		// Find the symbol
++		Elf_Xword     size;
++		unsigned char bind;
++		unsigned char symbolType;
++		Elf_Half      section;
++		unsigned char other;
++
++		symbol_section_accessor symbols(
++			elf_file, elf_file.sections[get_symbol_table_index()] );
++		ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size,
++										 bind, symbolType, section, other );
++
++		if ( ret ) { // Was it successful?
++			switch ( type ) {
++			case R_386_NONE: // none
++				calcValue = 0;
++				break;
++			case R_386_32: // S + A
++				calcValue = symbolValue + addend;
++				break;
++			case R_386_PC32: // S + A - P
++				calcValue = symbolValue + addend - offset;
++				break;
++			case R_386_GOT32: // G + A - P
++				calcValue = 0;
++				break;
++			case R_386_PLT32: // L + A - P
++				calcValue = 0;
++				break;
++			case R_386_COPY: // none
++				calcValue = 0;
++				break;
++			case R_386_GLOB_DAT: // S
++			case R_386_JMP_SLOT: // S
++				calcValue = symbolValue;
++				break;
++			case R_386_RELATIVE: // B + A
++				calcValue = addend;
++				break;
++			case R_386_GOTOFF: // S + A - GOT
++				calcValue = 0;
++				break;
++			case R_386_GOTPC: // GOT + A - P
++				calcValue = 0;
++				break;
++			default: // Not recognized symbol!
++				calcValue = 0;
++				break;
++			}
++		}
++
++		return ret;
++	}
++
++	//------------------------------------------------------------------------------
++	bool set_entry( Elf_Xword  index,
++					Elf64_Addr offset,
++					Elf_Word   symbol,
++					Elf_Word   type,
++					Elf_Sxword addend )
++	{
++		if ( index >= get_entries_num() ) { // Is index valid
++			return false;
++		}
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			if ( SHT_REL == relocation_section->get_type() ) {
++				generic_set_entry_rel<Elf32_Rel>( index, offset, symbol, type,
++												  addend );
++			}
++			else if ( SHT_RELA == relocation_section->get_type() ) {
++				generic_set_entry_rela<Elf32_Rela>( index, offset, symbol, type,
++													addend );
++			}
++		}
++		else {
++			if ( SHT_REL == relocation_section->get_type() ) {
++				generic_set_entry_rel<Elf64_Rel>( index, offset, symbol, type,
++												  addend );
++			}
++			else if ( SHT_RELA == relocation_section->get_type() ) {
++				generic_set_entry_rela<Elf64_Rela>( index, offset, symbol, type,
++													addend );
++			}
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf64_Addr offset, Elf_Xword info )
++	{
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			generic_add_entry<Elf32_Rel>( offset, info );
++		}
++		else {
++			generic_add_entry<Elf64_Rel>( offset, info );
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type )
++	{
++		Elf_Xword info;
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			info = ELF32_R_INFO( (Elf_Xword)symbol, type );
++		}
++		else {
++			info = ELF64_R_INFO( (Elf_Xword)symbol, type );
++		}
++
++		add_entry( offset, info );
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
++	{
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			generic_add_entry<Elf32_Rela>( offset, info, addend );
++		}
++		else {
++			generic_add_entry<Elf64_Rela>( offset, info, addend );
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf64_Addr    offset,
++					Elf_Word      symbol,
++					unsigned char type,
++					Elf_Sxword    addend )
++	{
++		Elf_Xword info;
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			info = ELF32_R_INFO( (Elf_Xword)symbol, type );
++		}
++		else {
++			info = ELF64_R_INFO( (Elf_Xword)symbol, type );
++		}
++
++		add_entry( offset, info, addend );
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( string_section_accessor str_writer,
++					const char*             str,
++					symbol_section_accessor sym_writer,
++					Elf64_Addr              value,
++					Elf_Word                size,
++					unsigned char           sym_info,
++					unsigned char           other,
++					Elf_Half                shndx,
++					Elf64_Addr              offset,
++					unsigned char           type )
++	{
++		Elf_Word str_index = str_writer.add_string( str );
++		Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size,
++													sym_info, other, shndx );
++		add_entry( offset, sym_index, type );
++	}
++
++	//------------------------------------------------------------------------------
++	void swap_symbols( Elf_Xword first, Elf_Xword second )
++	{
++		Elf64_Addr offset;
++		Elf_Word   symbol;
++		Elf_Word   rtype;
++		Elf_Sxword addend;
++		for ( Elf_Word i = 0; i < get_entries_num(); i++ ) {
++			get_entry( i, offset, symbol, rtype, addend );
++			if ( symbol == first ) {
++				set_entry( i, offset, (Elf_Word)second, rtype, addend );
++			}
++			if ( symbol == second ) {
++				set_entry( i, offset, (Elf_Word)first, rtype, addend );
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	Elf_Half get_symbol_table_index() const
++	{
++		return (Elf_Half)relocation_section->get_link();
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_get_entry_rel( Elf_Xword   index,
++								Elf64_Addr& offset,
++								Elf_Word&   symbol,
++								Elf_Word&   type,
++								Elf_Sxword& addend ) const
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		const T* pEntry = reinterpret_cast<const T*>(
++			relocation_section->get_data() +
++			index * relocation_section->get_entry_size() );
++		offset        = convertor( pEntry->r_offset );
++		Elf_Xword tmp = convertor( pEntry->r_info );
++		symbol        = get_sym_and_type<T>::get_r_sym( tmp );
++		type          = get_sym_and_type<T>::get_r_type( tmp );
++		addend        = 0;
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_get_entry_rela( Elf_Xword   index,
++								 Elf64_Addr& offset,
++								 Elf_Word&   symbol,
++								 Elf_Word&   type,
++								 Elf_Sxword& addend ) const
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		const T* pEntry = reinterpret_cast<const T*>(
++			relocation_section->get_data() +
++			index * relocation_section->get_entry_size() );
++		offset        = convertor( pEntry->r_offset );
++		Elf_Xword tmp = convertor( pEntry->r_info );
++		symbol        = get_sym_and_type<T>::get_r_sym( tmp );
++		type          = get_sym_and_type<T>::get_r_type( tmp );
++		addend        = convertor( pEntry->r_addend );
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_set_entry_rel( Elf_Xword  index,
++								Elf64_Addr offset,
++								Elf_Word   symbol,
++								Elf_Word   type,
++								Elf_Sxword )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
++			relocation_section->get_data() +
++			index * relocation_section->get_entry_size() ) );
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
++		}
++		else {
++			pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
++		}
++		pEntry->r_offset = offset;
++		pEntry->r_offset = convertor( pEntry->r_offset );
++		pEntry->r_info   = convertor( pEntry->r_info );
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_set_entry_rela( Elf_Xword  index,
++								 Elf64_Addr offset,
++								 Elf_Word   symbol,
++								 Elf_Word   type,
++								 Elf_Sxword addend )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T* pEntry = const_cast<T*>( reinterpret_cast<const T*>(
++			relocation_section->get_data() +
++			index * relocation_section->get_entry_size() ) );
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type );
++		}
++		else {
++			pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type );
++		}
++		pEntry->r_offset = offset;
++		pEntry->r_addend = addend;
++		pEntry->r_offset = convertor( pEntry->r_offset );
++		pEntry->r_info   = convertor( pEntry->r_info );
++		pEntry->r_addend = convertor( pEntry->r_addend );
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_add_entry( Elf64_Addr offset, Elf_Xword info )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T entry;
++		entry.r_offset = offset;
++		entry.r_info   = info;
++		entry.r_offset = convertor( entry.r_offset );
++		entry.r_info   = convertor( entry.r_info );
++
++		relocation_section->append_data( reinterpret_cast<char*>( &entry ),
++										 sizeof( entry ) );
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void
++	generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T entry;
++		entry.r_offset = offset;
++		entry.r_info   = info;
++		entry.r_addend = addend;
++		entry.r_offset = convertor( entry.r_offset );
++		entry.r_info   = convertor( entry.r_info );
++		entry.r_addend = convertor( entry.r_addend );
++
++		relocation_section->append_data( reinterpret_cast<char*>( &entry ),
++										 sizeof( entry ) );
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	const elfio& elf_file;
++	S*           relocation_section;
++};
++
++using relocation_section_accessor =
++	relocation_section_accessor_template<section>;
++using const_relocation_section_accessor =
++	relocation_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_RELOCATION_HPP
++
++/*** End of inlined file: elfio_relocation.hpp ***/
++
++
++/*** Start of inlined file: elfio_dynamic.hpp ***/
++#ifndef ELFIO_DYNAMIC_HPP
++#define ELFIO_DYNAMIC_HPP
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++template <class S> class dynamic_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	dynamic_section_accessor_template( const elfio& elf_file_, S* section_ )
++		: elf_file( elf_file_ ), dynamic_section( section_ )
++	{
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Xword get_entries_num() const
++	{
++		Elf_Xword nRet = 0;
++
++		if ( 0 != dynamic_section->get_entry_size() ) {
++			nRet =
++				dynamic_section->get_size() / dynamic_section->get_entry_size();
++		}
++
++		return nRet;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_entry( Elf_Xword    index,
++					Elf_Xword&   tag,
++					Elf_Xword&   value,
++					std::string& str ) const
++	{
++		if ( index >= get_entries_num() ) { // Is index valid
++			return false;
++		}
++
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			generic_get_entry_dyn<Elf32_Dyn>( index, tag, value );
++		}
++		else {
++			generic_get_entry_dyn<Elf64_Dyn>( index, tag, value );
++		}
++
++		// If the tag may have a string table reference, prepare the string
++		if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH ||
++			 tag == DT_RUNPATH ) {
++			string_section_accessor strsec =
++				elf_file.sections[get_string_table_index()];
++			const char* result = strsec.get_string( value );
++			if ( 0 == result ) {
++				str.clear();
++				return false;
++			}
++			str = result;
++		}
++		else {
++			str.clear();
++		}
++
++		return true;
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf_Xword tag, Elf_Xword value )
++	{
++		if ( elf_file.get_class() == ELFCLASS32 ) {
++			generic_add_entry<Elf32_Dyn>( tag, value );
++		}
++		else {
++			generic_add_entry<Elf64_Dyn>( tag, value );
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	void add_entry( Elf_Xword tag, const std::string& str )
++	{
++		string_section_accessor strsec =
++			elf_file.sections[get_string_table_index()];
++		Elf_Xword value = strsec.add_string( str );
++		add_entry( tag, value );
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	//------------------------------------------------------------------------------
++	Elf_Half get_string_table_index() const
++	{
++		return (Elf_Half)dynamic_section->get_link();
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T>
++	void generic_get_entry_dyn( Elf_Xword  index,
++								Elf_Xword& tag,
++								Elf_Xword& value ) const
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		// Check unusual case when dynamic section has no data
++		if ( dynamic_section->get_data() == 0 ||
++			 ( index + 1 ) * dynamic_section->get_entry_size() >
++				 dynamic_section->get_size() ) {
++			tag   = DT_NULL;
++			value = 0;
++			return;
++		}
++
++		const T* pEntry = reinterpret_cast<const T*>(
++			dynamic_section->get_data() +
++			index * dynamic_section->get_entry_size() );
++		tag = convertor( pEntry->d_tag );
++		switch ( tag ) {
++		case DT_NULL:
++		case DT_SYMBOLIC:
++		case DT_TEXTREL:
++		case DT_BIND_NOW:
++			value = 0;
++			break;
++		case DT_NEEDED:
++		case DT_PLTRELSZ:
++		case DT_RELASZ:
++		case DT_RELAENT:
++		case DT_STRSZ:
++		case DT_SYMENT:
++		case DT_SONAME:
++		case DT_RPATH:
++		case DT_RELSZ:
++		case DT_RELENT:
++		case DT_PLTREL:
++		case DT_INIT_ARRAYSZ:
++		case DT_FINI_ARRAYSZ:
++		case DT_RUNPATH:
++		case DT_FLAGS:
++		case DT_PREINIT_ARRAYSZ:
++			value = convertor( pEntry->d_un.d_val );
++			break;
++		case DT_PLTGOT:
++		case DT_HASH:
++		case DT_STRTAB:
++		case DT_SYMTAB:
++		case DT_RELA:
++		case DT_INIT:
++		case DT_FINI:
++		case DT_REL:
++		case DT_DEBUG:
++		case DT_JMPREL:
++		case DT_INIT_ARRAY:
++		case DT_FINI_ARRAY:
++		case DT_PREINIT_ARRAY:
++		default:
++			value = convertor( pEntry->d_un.d_ptr );
++			break;
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	template <class T> void generic_add_entry( Elf_Xword tag, Elf_Xword value )
++	{
++		const endianess_convertor& convertor = elf_file.get_convertor();
++
++		T entry;
++
++		switch ( tag ) {
++		case DT_NULL:
++		case DT_SYMBOLIC:
++		case DT_TEXTREL:
++		case DT_BIND_NOW:
++			value = 0;
++		case DT_NEEDED:
++		case DT_PLTRELSZ:
++		case DT_RELASZ:
++		case DT_RELAENT:
++		case DT_STRSZ:
++		case DT_SYMENT:
++		case DT_SONAME:
++		case DT_RPATH:
++		case DT_RELSZ:
++		case DT_RELENT:
++		case DT_PLTREL:
++		case DT_INIT_ARRAYSZ:
++		case DT_FINI_ARRAYSZ:
++		case DT_RUNPATH:
++		case DT_FLAGS:
++		case DT_PREINIT_ARRAYSZ:
++			entry.d_un.d_val = convertor( value );
++			break;
++		case DT_PLTGOT:
++		case DT_HASH:
++		case DT_STRTAB:
++		case DT_SYMTAB:
++		case DT_RELA:
++		case DT_INIT:
++		case DT_FINI:
++		case DT_REL:
++		case DT_DEBUG:
++		case DT_JMPREL:
++		case DT_INIT_ARRAY:
++		case DT_FINI_ARRAY:
++		case DT_PREINIT_ARRAY:
++		default:
++			entry.d_un.d_ptr = convertor( value );
++			break;
++		}
++
++		entry.d_tag = convertor( tag );
++
++		dynamic_section->append_data( reinterpret_cast<char*>( &entry ),
++									  sizeof( entry ) );
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	const elfio& elf_file;
++	S*           dynamic_section;
++};
++
++using dynamic_section_accessor = dynamic_section_accessor_template<section>;
++using const_dynamic_section_accessor =
++	dynamic_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_DYNAMIC_HPP
++
++/*** End of inlined file: elfio_dynamic.hpp ***/
++
++
++/*** Start of inlined file: elfio_modinfo.hpp ***/
++#ifndef ELFIO_MODINFO_HPP
++#define ELFIO_MODINFO_HPP
++
++#include <string>
++#include <vector>
++
++namespace ELFIO {
++
++//------------------------------------------------------------------------------
++template <class S> class modinfo_section_accessor_template
++{
++  public:
++	//------------------------------------------------------------------------------
++	modinfo_section_accessor_template( S* section_ )
++		: modinfo_section( section_ )
++	{
++		process_section();
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); }
++
++	//------------------------------------------------------------------------------
++	bool
++	get_attribute( Elf_Word no, std::string& field, std::string& value ) const
++	{
++		if ( no < content.size() ) {
++			field = content[no].first;
++			value = content[no].second;
++			return true;
++		}
++
++		return false;
++	}
++
++	//------------------------------------------------------------------------------
++	bool get_attribute( std::string field_name, std::string& value ) const
++	{
++		for ( auto i = content.begin(); i != content.end(); i++ ) {
++			if ( field_name == i->first ) {
++				value = i->second;
++				return true;
++			}
++		}
++
++		return false;
++	}
++
++	//------------------------------------------------------------------------------
++	Elf_Word add_attribute( std::string field, std::string value )
++	{
++		Elf_Word current_position = 0;
++
++		if ( modinfo_section ) {
++			// Strings are addeded to the end of the current section data
++			current_position = (Elf_Word)modinfo_section->get_size();
++
++			std::string attribute = field + "=" + value;
++
++			modinfo_section->append_data( attribute + '\0' );
++			content.push_back(
++				std::pair<std::string, std::string>( field, value ) );
++		}
++
++		return current_position;
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	void process_section()
++	{
++		const char* pdata = modinfo_section->get_data();
++		if ( pdata ) {
++			ELFIO::Elf_Xword i = 0;
++			while ( i < modinfo_section->get_size() ) {
++				while ( i < modinfo_section->get_size() && !pdata[i] )
++					i++;
++				if ( i < modinfo_section->get_size() ) {
++					std::string                         info = pdata + i;
++					size_t                              loc  = info.find( '=' );
++					std::pair<std::string, std::string> attribute(
++						info.substr( 0, loc ), info.substr( loc + 1 ) );
++
++					content.push_back( attribute );
++
++					i += info.length();
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++  private:
++	S*                                               modinfo_section;
++	std::vector<std::pair<std::string, std::string>> content;
++};
++
++using modinfo_section_accessor = modinfo_section_accessor_template<section>;
++using const_modinfo_section_accessor =
++	modinfo_section_accessor_template<const section>;
++
++} // namespace ELFIO
++
++#endif // ELFIO_MODINFO_HPP
++
++/*** End of inlined file: elfio_modinfo.hpp ***/
++
++#ifdef _MSC_VER
++#pragma warning( pop )
++#endif
++
++#endif // ELFIO_HPP
++
++/*** End of inlined file: elfio.hpp ***/
++
++
++namespace ELFIO {
++
++static struct class_table_t
++{
++	const char  key;
++	const char* str;
++} class_table[] = {
++	{ ELFCLASS32, "ELF32" },
++	{ ELFCLASS64, "ELF64" },
++};
++
++static struct endian_table_t
++{
++	const char  key;
++	const char* str;
++} endian_table[] = {
++	{ ELFDATANONE, "None" },
++	{ ELFDATA2LSB, "Little endian" },
++	{ ELFDATA2MSB, "Big endian" },
++};
++
++static struct version_table_t
++{
++	const Elf64_Word key;
++	const char*      str;
++} version_table[] = {
++	{ EV_NONE, "None" },
++	{ EV_CURRENT, "Current" },
++};
++
++static struct type_table_t
++{
++	const Elf32_Half key;
++	const char*      str;
++} type_table[] = {
++	{ ET_NONE, "No file type" },    { ET_REL, "Relocatable file" },
++	{ ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" },
++	{ ET_CORE, "Core file" },
++};
++
++static struct machine_table_t
++{
++	const Elf64_Half key;
++	const char*      str;
++} machine_table[] = {
++	{ EM_NONE, "No machine" },
++	{ EM_M32, "AT&T WE 32100" },
++	{ EM_SPARC, "SUN SPARC" },
++	{ EM_386, "Intel 80386" },
++	{ EM_68K, "Motorola m68k family" },
++	{ EM_88K, "Motorola m88k family" },
++	{ EM_486, "Intel 80486// Reserved for future use" },
++	{ EM_860, "Intel 80860" },
++	{ EM_MIPS, "MIPS R3000 (officially, big-endian only)" },
++	{ EM_S370, "IBM System/370" },
++	{ EM_MIPS_RS3_LE,
++	  "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" },
++	{ EM_res011, "Reserved" },
++	{ EM_res012, "Reserved" },
++	{ EM_res013, "Reserved" },
++	{ EM_res014, "Reserved" },
++	{ EM_PARISC, "HPPA" },
++	{ EM_res016, "Reserved" },
++	{ EM_VPP550, "Fujitsu VPP500" },
++	{ EM_SPARC32PLUS, "Sun's v8plus" },
++	{ EM_960, "Intel 80960" },
++	{ EM_PPC, "PowerPC" },
++	{ EM_PPC64, "64-bit PowerPC" },
++	{ EM_S390, "IBM S/390" },
++	{ EM_SPU, "Sony/Toshiba/IBM SPU" },
++	{ EM_res024, "Reserved" },
++	{ EM_res025, "Reserved" },
++	{ EM_res026, "Reserved" },
++	{ EM_res027, "Reserved" },
++	{ EM_res028, "Reserved" },
++	{ EM_res029, "Reserved" },
++	{ EM_res030, "Reserved" },
++	{ EM_res031, "Reserved" },
++	{ EM_res032, "Reserved" },
++	{ EM_res033, "Reserved" },
++	{ EM_res034, "Reserved" },
++	{ EM_res035, "Reserved" },
++	{ EM_V800, "NEC V800 series" },
++	{ EM_FR20, "Fujitsu FR20" },
++	{ EM_RH32, "TRW RH32" },
++	{ EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" },
++	{ EM_RCE, "Old name for MCore" },
++	{ EM_ARM, "ARM" },
++	{ EM_OLD_ALPHA, "Digital Alpha" },
++	{ EM_SH, "Renesas (formerly Hitachi) / SuperH SH" },
++	{ EM_SPARCV9, "SPARC v9 64-bit" },
++	{ EM_TRICORE, "Siemens Tricore embedded processor" },
++	{ EM_ARC, "ARC Cores" },
++	{ EM_H8_300, "Renesas (formerly Hitachi) H8/300" },
++	{ EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" },
++	{ EM_H8S, "Renesas (formerly Hitachi) H8S" },
++	{ EM_H8_500, "Renesas (formerly Hitachi) H8/500" },
++	{ EM_IA_64, "Intel IA-64 Processor" },
++	{ EM_MIPS_X, "Stanford MIPS-X" },
++	{ EM_COLDFIRE, "Motorola Coldfire" },
++	{ EM_68HC12, "Motorola M68HC12" },
++	{ EM_MMA, "Fujitsu Multimedia Accelerator" },
++	{ EM_PCP, "Siemens PCP" },
++	{ EM_NCPU, "Sony nCPU embedded RISC processor" },
++	{ EM_NDR1, "Denso NDR1 microprocesspr" },
++	{ EM_STARCORE, "Motorola Star*Core processor" },
++	{ EM_ME16, "Toyota ME16 processor" },
++	{ EM_ST100, "STMicroelectronics ST100 processor" },
++	{ EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" },
++	{ EM_X86_64, "Advanced Micro Devices X86-64 processor" },
++	{ EM_PDSP, "Sony DSP Processor" },
++	{ EM_PDP10, "Digital Equipment Corp. PDP-10" },
++	{ EM_PDP11, "Digital Equipment Corp. PDP-11" },
++	{ EM_FX66, "Siemens FX66 microcontroller" },
++	{ EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" },
++	{ EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" },
++	{ EM_68HC16, "Motorola MC68HC16 Microcontroller" },
++	{ EM_68HC11, "Motorola MC68HC11 Microcontroller" },
++	{ EM_68HC08, "Motorola MC68HC08 Microcontroller" },
++	{ EM_68HC05, "Motorola MC68HC05 Microcontroller" },
++	{ EM_SVX, "Silicon Graphics SVx" },
++	{ EM_ST19, "STMicroelectronics ST19 8-bit cpu" },
++	{ EM_VAX, "Digital VAX" },
++	{ EM_CRIS, "Axis Communications 32-bit embedded processor" },
++	{ EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" },
++	{ EM_FIREPATH, "Element 14 64-bit DSP processor" },
++	{ EM_ZSP, "LSI Logic's 16-bit DSP processor" },
++	{ EM_MMIX, "Donald Knuth's educational 64-bit processor" },
++	{ EM_HUANY, "Harvard's machine-independent format" },
++	{ EM_PRISM, "SiTera Prism" },
++	{ EM_AVR, "Atmel AVR 8-bit microcontroller" },
++	{ EM_FR30, "Fujitsu FR30" },
++	{ EM_D10V, "Mitsubishi D10V" },
++	{ EM_D30V, "Mitsubishi D30V" },
++	{ EM_V850, "NEC v850" },
++	{ EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" },
++	{ EM_MN10300, "Matsushita MN10300" },
++	{ EM_MN10200, "Matsushita MN10200" },
++	{ EM_PJ, "picoJava" },
++	{ EM_OPENRISC, "OpenRISC 32-bit embedded processor" },
++	{ EM_ARC_A5, "ARC Cores Tangent-A5" },
++	{ EM_XTENSA, "Tensilica Xtensa Architecture" },
++	{ EM_VIDEOCORE, "Alphamosaic VideoCore processor" },
++	{ EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" },
++	{ EM_NS32K, "National Semiconductor 32000 series" },
++	{ EM_TPC, "Tenor Network TPC processor" },
++	{ EM_SNP1K, "Trebia SNP 1000 processor" },
++	{ EM_ST200, "STMicroelectronics ST200 microcontroller" },
++	{ EM_IP2K, "Ubicom IP2022 micro controller" },
++	{ EM_MAX, "MAX Processor" },
++	{ EM_CR, "National Semiconductor CompactRISC" },
++	{ EM_F2MC16, "Fujitsu F2MC16" },
++	{ EM_MSP430, "TI msp430 micro controller" },
++	{ EM_BLACKFIN, "ADI Blackfin" },
++	{ EM_SE_C33, "S1C33 Family of Seiko Epson processors" },
++	{ EM_SEP, "Sharp embedded microprocessor" },
++	{ EM_ARCA, "Arca RISC Microprocessor" },
++	{ EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of "
++				  "Peking University" },
++	{ EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" },
++	{ EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" },
++	{ EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" },
++	{ EM_CRX, "National Semiconductor CRX" },
++	{ EM_XGATE, "Motorola XGATE embedded processor" },
++	{ EM_C166, "Infineon C16x/XC16x processor" },
++	{ EM_M16C, "Renesas M16C series microprocessors" },
++	{ EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" },
++	{ EM_CE, "Freescale Communication Engine RISC core" },
++	{ EM_M32C, "Renesas M32C series microprocessors" },
++	{ EM_res121, "Reserved" },
++	{ EM_res122, "Reserved" },
++	{ EM_res123, "Reserved" },
++	{ EM_res124, "Reserved" },
++	{ EM_res125, "Reserved" },
++	{ EM_res126, "Reserved" },
++	{ EM_res127, "Reserved" },
++	{ EM_res128, "Reserved" },
++	{ EM_res129, "Reserved" },
++	{ EM_res130, "Reserved" },
++	{ EM_TSK3000, "Altium TSK3000 core" },
++	{ EM_RS08, "Freescale RS08 embedded processor" },
++	{ EM_res133, "Reserved" },
++	{ EM_ECOG2, "Cyan Technology eCOG2 microprocessor" },
++	{ EM_SCORE, "Sunplus Score" },
++	{ EM_SCORE7, "Sunplus S+core7 RISC processor" },
++	{ EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" },
++	{ EM_VIDEOCORE3, "Broadcom VideoCore III processor" },
++	{ EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" },
++	{ EM_SE_C17, "Seiko Epson C17 family" },
++	{ EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" },
++	{ EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" },
++	{ EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" },
++	{ EM_res143, "Reserved" },
++	{ EM_res144, "Reserved" },
++	{ EM_res145, "Reserved" },
++	{ EM_res146, "Reserved" },
++	{ EM_res147, "Reserved" },
++	{ EM_res148, "Reserved" },
++	{ EM_res149, "Reserved" },
++	{ EM_res150, "Reserved" },
++	{ EM_res151, "Reserved" },
++	{ EM_res152, "Reserved" },
++	{ EM_res153, "Reserved" },
++	{ EM_res154, "Reserved" },
++	{ EM_res155, "Reserved" },
++	{ EM_res156, "Reserved" },
++	{ EM_res157, "Reserved" },
++	{ EM_res158, "Reserved" },
++	{ EM_res159, "Reserved" },
++	{ EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" },
++	{ EM_CYPRESS_M8C, "Cypress M8C microprocessor" },
++	{ EM_R32C, "Renesas R32C series microprocessors" },
++	{ EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" },
++	{ EM_QDSP6, "QUALCOMM DSP6 Processor" },
++	{ EM_8051, "Intel 8051 and variants" },
++	{ EM_STXP7X, "STMicroelectronics STxP7x family" },
++	{ EM_NDS32,
++	  "Andes Technology compact code size embedded RISC processor family" },
++	{ EM_ECOG1, "Cyan Technology eCOG1X family" },
++	{ EM_ECOG1X, "Cyan Technology eCOG1X family" },
++	{ EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" },
++	{ EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" },
++	{ EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" },
++	{ EM_CRAYNV2, "Cray Inc. NV2 vector architecture" },
++	{ EM_RX, "Renesas RX family" },
++	{ EM_METAG, "Imagination Technologies META processor architecture" },
++	{ EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" },
++	{ EM_ECOG16, "Cyan Technology eCOG16 family" },
++	{ EM_CR16, "National Semiconductor CompactRISC 16-bit processor" },
++	{ EM_ETPU, "Freescale Extended Time Processing Unit" },
++	{ EM_SLE9X, "Infineon Technologies SLE9X core" },
++	{ EM_L1OM, "Intel L1OM" },
++	{ EM_INTEL181, "Reserved by Intel" },
++	{ EM_INTEL182, "Reserved by Intel" },
++	{ EM_res183, "Reserved by ARM" },
++	{ EM_res184, "Reserved by ARM" },
++	{ EM_AVR32, "Atmel Corporation 32-bit microprocessor family" },
++	{ EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" },
++	{ EM_TILE64, "Tilera TILE64 multicore architecture family" },
++	{ EM_TILEPRO, "Tilera TILEPro multicore architecture family" },
++	{ EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" },
++	{ EM_CUDA, "NVIDIA CUDA architecture " },
++};
++
++static struct section_type_table_t
++{
++	const Elf64_Half key;
++	const char*      str;
++} section_type_table[] = {
++	{ SHT_NULL, "NULL" },
++	{ SHT_PROGBITS, "PROGBITS" },
++	{ SHT_SYMTAB, "SYMTAB" },
++	{ SHT_STRTAB, "STRTAB" },
++	{ SHT_RELA, "RELA" },
++	{ SHT_HASH, "HASH" },
++	{ SHT_DYNAMIC, "DYNAMIC" },
++	{ SHT_NOTE, "NOTE" },
++	{ SHT_NOBITS, "NOBITS" },
++	{ SHT_REL, "REL" },
++	{ SHT_SHLIB, "SHLIB" },
++	{ SHT_DYNSYM, "DYNSYM" },
++	{ SHT_INIT_ARRAY, "INIT_ARRAY" },
++	{ SHT_FINI_ARRAY, "FINI_ARRAY" },
++	{ SHT_PREINIT_ARRAY, "PREINIT_ARRAY" },
++	{ SHT_GROUP, "GROUP" },
++	{ SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX " },
++};
++
++static struct segment_type_table_t
++{
++	const Elf_Word key;
++	const char*    str;
++} segment_type_table[] = {
++	{ PT_NULL, "NULL" },     { PT_LOAD, "LOAD" }, { PT_DYNAMIC, "DYNAMIC" },
++	{ PT_INTERP, "INTERP" }, { PT_NOTE, "NOTE" }, { PT_SHLIB, "SHLIB" },
++	{ PT_PHDR, "PHDR" },     { PT_TLS, "TLS" },
++};
++
++static struct segment_flag_table_t
++{
++	const Elf_Word key;
++	const char*    str;
++} segment_flag_table[] = {
++	{ 0, "" },  { 1, "X" },  { 2, "W" },  { 3, "WX" },
++	{ 4, "R" }, { 5, "RX" }, { 6, "RW" }, { 7, "RWX" },
++};
++
++static struct symbol_bind_t
++{
++	const Elf_Word key;
++	const char*    str;
++} symbol_bind_table[] = {
++	{ STB_LOCAL, "LOCAL" },   { STB_GLOBAL, "GLOBAL" },
++	{ STB_WEAK, "WEAK" },     { STB_LOOS, "LOOS" },
++	{ STB_HIOS, "HIOS" },     { STB_MULTIDEF, "MULTIDEF" },
++	{ STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" },
++};
++
++static struct symbol_type_t
++{
++	const Elf_Word key;
++	const char*    str;
++} symbol_type_table[] = {
++	{ STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" },
++	{ STT_FUNC, "FUNC" },     { STT_SECTION, "SECTION" },
++	{ STT_FILE, "FILE" },     { STT_COMMON, "COMMON" },
++	{ STT_TLS, "TLS" },       { STT_LOOS, "LOOS" },
++	{ STT_HIOS, "HIOS" },     { STT_LOPROC, "LOPROC" },
++	{ STT_HIPROC, "HIPROC" },
++};
++
++static struct dynamic_tag_t
++{
++	const Elf_Word key;
++	const char*    str;
++} dynamic_tag_table[] = {
++	{ DT_NULL, "NULL" },
++	{ DT_NEEDED, "NEEDED" },
++	{ DT_PLTRELSZ, "PLTRELSZ" },
++	{ DT_PLTGOT, "PLTGOT" },
++	{ DT_HASH, "HASH" },
++	{ DT_STRTAB, "STRTAB" },
++	{ DT_SYMTAB, "SYMTAB" },
++	{ DT_RELA, "RELA" },
++	{ DT_RELASZ, "RELASZ" },
++	{ DT_RELAENT, "RELAENT" },
++	{ DT_STRSZ, "STRSZ" },
++	{ DT_SYMENT, "SYMENT" },
++	{ DT_INIT, "INIT" },
++	{ DT_FINI, "FINI" },
++	{ DT_SONAME, "SONAME" },
++	{ DT_RPATH, "RPATH" },
++	{ DT_SYMBOLIC, "SYMBOLIC" },
++	{ DT_REL, "REL" },
++	{ DT_RELSZ, "RELSZ" },
++	{ DT_RELENT, "RELENT" },
++	{ DT_PLTREL, "PLTREL" },
++	{ DT_DEBUG, "DEBUG" },
++	{ DT_TEXTREL, "TEXTREL" },
++	{ DT_JMPREL, "JMPREL" },
++	{ DT_BIND_NOW, "BIND_NOW" },
++	{ DT_INIT_ARRAY, "INIT_ARRAY" },
++	{ DT_FINI_ARRAY, "FINI_ARRAY" },
++	{ DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" },
++	{ DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" },
++	{ DT_RUNPATH, "RUNPATH" },
++	{ DT_FLAGS, "FLAGS" },
++	{ DT_ENCODING, "ENCODING" },
++	{ DT_PREINIT_ARRAY, "PREINIT_ARRAY" },
++	{ DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" },
++	{ DT_MAXPOSTAGS, "MAXPOSTAGS" },
++};
++
++static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64;
++
++//------------------------------------------------------------------------------
++class dump
++{
++#define DUMP_DEC_FORMAT( width ) \
++	std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right
++#define DUMP_HEX_FORMAT( width ) \
++	std::setw( width ) << std::setfill( '0' ) << std::hex << std::right
++#define DUMP_STR_FORMAT( width ) \
++	std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left
++
++  public:
++	//------------------------------------------------------------------------------
++	static void header( std::ostream& out, const elfio& reader )
++	{
++		if ( !reader.get_header_size() ) {
++			return;
++		}
++		out << "ELF Header" << std::endl
++			<< std::endl
++			<< "  Class:      " << str_class( reader.get_class() ) << std::endl
++			<< "  Encoding:   " << str_endian( reader.get_encoding() )
++			<< std::endl
++			<< "  ELFVersion: " << str_version( reader.get_elf_version() )
++			<< std::endl
++			<< "  Type:       " << str_type( reader.get_type() ) << std::endl
++			<< "  Machine:    " << str_machine( reader.get_machine() )
++			<< std::endl
++			<< "  Version:    " << str_version( reader.get_version() )
++			<< std::endl
++			<< "  Entry:      "
++			<< "0x" << std::hex << reader.get_entry() << std::endl
++			<< "  Flags:      "
++			<< "0x" << std::hex << reader.get_flags() << std::endl
++			<< std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void section_headers( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.sections.size();
++
++		if ( n == 0 ) {
++			return;
++		}
++
++		out << "Section Headers:" << std::endl;
++		if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit
++			out << "[  Nr ] Type              Addr     Size     ES Flg Lk Inf "
++				   "Al Name"
++				<< std::endl;
++		}
++		else { // Output for 64-bit
++			out << "[  Nr ] Type              Addr             Size            "
++				   " ES   Flg"
++				<< std::endl
++				<< "        Lk   Inf  Al      Name" << std::endl;
++		}
++
++		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			section_header( out, i, sec, reader.get_class() );
++		}
++
++		out << "Key to Flags: W (write), A (alloc), X (execute)\n\n"
++			<< std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void section_header( std::ostream&  out,
++								Elf_Half       no,
++								const section* sec,
++								unsigned char  elf_class )
++	{
++		std::ios_base::fmtflags original_flags = out.flags();
++
++		if ( elf_class == ELFCLASS32 ) { // Output for 32-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() )
++				<< " " << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " "
++				<< DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " "
++				<< DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " "
++				<< DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() )
++				<< " " << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " "
++				<< DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " "
++				<< DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " "
++				<< DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl;
++		}
++		else { // Output for 64-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() )
++				<< " " << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " "
++				<< DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " "
++				<< DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " "
++				<< DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() )
++				<< " " << std::endl
++				<< "        " << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " "
++				<< DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " "
++				<< DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << "    "
++				<< DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl;
++		}
++
++		out.flags( original_flags );
++
++		return;
++	}
++
++	//------------------------------------------------------------------------------
++	static void segment_headers( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.segments.size();
++		if ( n == 0 ) {
++			return;
++		}
++
++		out << "Segment headers:" << std::endl;
++		if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit
++			out << "[  Nr ] Type           VirtAddr PhysAddr FileSize Mem.Size "
++				   "Flags    Align"
++				<< std::endl;
++		}
++		else { // Output for 64-bit
++			out << "[  Nr ] Type           VirtAddr         PhysAddr         "
++				   "Flags"
++				<< std::endl
++				<< "                       FileSize         Mem.Size         "
++				   "Align"
++				<< std::endl;
++		}
++
++		for ( Elf_Half i = 0; i < n; ++i ) {
++			segment* seg = reader.segments[i];
++			segment_header( out, i, seg, reader.get_class() );
++		}
++
++		out << std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void segment_header( std::ostream&  out,
++								Elf_Half       no,
++								const segment* seg,
++								unsigned int   elf_class )
++	{
++		std::ios_base::fmtflags original_flags = out.flags();
++
++		if ( elf_class == ELFCLASS32 ) { // Output for 32-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() )
++				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address()
++				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address()
++				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " "
++				<< DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " "
++				<< DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() )
++				<< " " << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " "
++				<< std::endl;
++		}
++		else { // Output for 64-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() )
++				<< " " << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address()
++				<< " " << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address()
++				<< " " << DUMP_STR_FORMAT( 16 )
++				<< str_segment_flag( seg->get_flags() ) << " " << std::endl
++				<< "                       " << DUMP_HEX_FORMAT( 16 )
++				<< seg->get_file_size() << " " << DUMP_HEX_FORMAT( 16 )
++				<< seg->get_memory_size() << " " << DUMP_HEX_FORMAT( 16 )
++				<< seg->get_align() << " " << std::endl;
++		}
++
++		out.flags( original_flags );
++	}
++
++	//------------------------------------------------------------------------------
++	static void symbol_tables( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.sections.size();
++		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			if ( SHT_SYMTAB == sec->get_type() ||
++				 SHT_DYNSYM == sec->get_type() ) {
++				symbol_section_accessor symbols( reader, sec );
++
++				Elf_Xword sym_no = symbols.get_symbols_num();
++				if ( sym_no > 0 ) {
++					out << "Symbol table (" << sec->get_name() << ")"
++						<< std::endl;
++					if ( reader.get_class() ==
++						 ELFCLASS32 ) { // Output for 32-bit
++						out << "[  Nr ] Value    Size     Type    Bind      "
++							   "Sect Name"
++							<< std::endl;
++					}
++					else { // Output for 64-bit
++						out << "[  Nr ] Value            Size             Type "
++							   "   Bind      Sect"
++							<< std::endl
++							<< "        Name" << std::endl;
++					}
++					for ( Elf_Xword i = 0; i < sym_no; ++i ) {
++						std::string   name;
++						Elf64_Addr    value   = 0;
++						Elf_Xword     size    = 0;
++						unsigned char bind    = 0;
++						unsigned char type    = 0;
++						Elf_Half      section = 0;
++						unsigned char other   = 0;
++						symbols.get_symbol( i, name, value, size, bind, type,
++											section, other );
++						symbol_table( out, i, name, value, size, bind, type,
++									  section, reader.get_class() );
++					}
++
++					out << std::endl;
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	static void symbol_table( std::ostream& out,
++							  Elf_Xword     no,
++							  std::string&  name,
++							  Elf64_Addr    value,
++							  Elf_Xword     size,
++							  unsigned char bind,
++							  unsigned char type,
++							  Elf_Half      section,
++							  unsigned int  elf_class )
++	{
++		std::ios_base::fmtflags original_flags = out.flags();
++
++		if ( elf_class == ELFCLASS32 ) { // Output for 32-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_HEX_FORMAT( 8 ) << value << " " << DUMP_HEX_FORMAT( 8 )
++				<< size << " " << DUMP_STR_FORMAT( 7 )
++				<< str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 )
++				<< str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 )
++				<< section << " " << DUMP_STR_FORMAT( 1 ) << name << " "
++				<< std::endl;
++		}
++		else { // Output for 64-bit
++			out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++				<< DUMP_HEX_FORMAT( 16 ) << value << " "
++				<< DUMP_HEX_FORMAT( 16 ) << size << " " << DUMP_STR_FORMAT( 7 )
++				<< str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 )
++				<< str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 )
++				<< section << " " << std::endl
++				<< "        " << DUMP_STR_FORMAT( 1 ) << name << " "
++				<< std::endl;
++		}
++
++		out.flags( original_flags );
++	}
++
++	//------------------------------------------------------------------------------
++	static void notes( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half no = reader.sections.size();
++		for ( Elf_Half i = 0; i < no; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			if ( SHT_NOTE == sec->get_type() ) { // Look at notes
++				note_section_accessor notes( reader, sec );
++				Elf_Word              no_notes = notes.get_notes_num();
++				if ( no > 0 ) {
++					out << "Note section (" << sec->get_name() << ")"
++						<< std::endl
++						<< "    No Type     Name" << std::endl;
++					for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes
++						Elf_Word    type;
++						std::string name;
++						void*       desc;
++						Elf_Word    descsz;
++
++						if ( notes.get_note( j, type, name, desc, descsz ) ) {
++							// 'name' usually contains \0 at the end. Try to fix it
++							name = name.c_str();
++							note( out, j, type, name );
++						}
++					}
++
++					out << std::endl;
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	static void modinfo( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half no = reader.sections.size();
++		for ( Elf_Half i = 0; i < no; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			if ( ".modinfo" == sec->get_name() ) { // Look for the section
++				out << "Section .modinfo" << std::endl;
++
++				const_modinfo_section_accessor modinfo( sec );
++				for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) {
++					std::string field;
++					std::string value;
++					if ( modinfo.get_attribute( i, field, value ) ) {
++						out << "  " << std::setw( 20 ) << field
++							<< std::setw( 0 ) <<  " = " << value << std::endl;
++					}
++				}
++
++				out << std::endl;
++				break;
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	static void
++	note( std::ostream& out, int no, Elf_Word type, const std::string& name )
++	{
++		out << "  [" << DUMP_DEC_FORMAT( 2 ) << no << "] "
++			<< DUMP_HEX_FORMAT( 8 ) << type << " " << DUMP_STR_FORMAT( 1 )
++			<< name << std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void dynamic_tags( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.sections.size();
++		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			if ( SHT_DYNAMIC == sec->get_type() ) {
++				dynamic_section_accessor dynamic( reader, sec );
++
++				Elf_Xword dyn_no = dynamic.get_entries_num();
++				if ( dyn_no > 0 ) {
++					out << "Dynamic section (" << sec->get_name() << ")"
++						<< std::endl;
++					out << "[  Nr ] Tag              Name/Value" << std::endl;
++					for ( Elf_Xword i = 0; i < dyn_no; ++i ) {
++						Elf_Xword   tag   = 0;
++						Elf_Xword   value = 0;
++						std::string str;
++						dynamic.get_entry( i, tag, value, str );
++						dynamic_tag( out, i, tag, value, str,
++									 reader.get_class() );
++						if ( DT_NULL == tag ) {
++							break;
++						}
++					}
++
++					out << std::endl;
++				}
++			}
++		}
++	}
++
++	//------------------------------------------------------------------------------
++	static void dynamic_tag( std::ostream& out,
++							 Elf_Xword     no,
++							 Elf_Xword     tag,
++							 Elf_Xword     value,
++							 std::string   str,
++							 unsigned int /*elf_class*/ )
++	{
++		out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] "
++			<< DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " ";
++		if ( str.empty() ) {
++			out << DUMP_HEX_FORMAT( 16 ) << value << " ";
++		}
++		else {
++			out << DUMP_STR_FORMAT( 32 ) << str << " ";
++		}
++		out << std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void section_data( std::ostream& out, const section* sec )
++	{
++		std::ios_base::fmtflags original_flags = out.flags();
++
++		out << sec->get_name() << std::endl;
++		const char* pdata = sec->get_data();
++		if ( pdata ) {
++			ELFIO::Elf_Xword i;
++			for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES );
++				  ++i ) {
++				if ( i % 16 == 0 ) {
++					out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]";
++				}
++
++				out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF );
++
++				if ( i % 16 == 15 ) {
++					out << std::endl;
++				}
++			}
++			if ( i % 16 != 0 ) {
++				out << std::endl;
++			}
++
++			out.flags( original_flags );
++		}
++
++		return;
++	}
++
++	//------------------------------------------------------------------------------
++	static void section_datas( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.sections.size();
++
++		if ( n == 0 ) {
++			return;
++		}
++
++		out << "Section Data:" << std::endl;
++
++		for ( Elf_Half i = 1; i < n; ++i ) { // For all sections
++			section* sec = reader.sections[i];
++			if ( sec->get_type() == SHT_NOBITS ) {
++				continue;
++			}
++			section_data( out, sec );
++		}
++
++		out << std::endl;
++	}
++
++	//------------------------------------------------------------------------------
++	static void
++	segment_data( std::ostream& out, Elf_Half no, const segment* seg )
++	{
++		std::ios_base::fmtflags original_flags = out.flags();
++
++		out << "Segment # " << no << std::endl;
++		const char* pdata = seg->get_data();
++		if ( pdata ) {
++			ELFIO::Elf_Xword i;
++			for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES );
++				  ++i ) {
++				if ( i % 16 == 0 ) {
++					out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]";
++				}
++
++				out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF );
++
++				if ( i % 16 == 15 ) {
++					out << std::endl;
++				}
++			}
++			if ( i % 16 != 0 ) {
++				out << std::endl;
++			}
++
++			out.flags( original_flags );
++		}
++
++		return;
++	}
++
++	//------------------------------------------------------------------------------
++	static void segment_datas( std::ostream& out, const elfio& reader )
++	{
++		Elf_Half n = reader.segments.size();
++
++		if ( n == 0 ) {
++			return;
++		}
++
++		out << "Segment Data:" << std::endl;
++
++		for ( Elf_Half i = 0; i < n; ++i ) { // For all sections
++			segment* seg = reader.segments[i];
++			segment_data( out, i, seg );
++		}
++
++		out << std::endl;
++	}
++
++  private:
++	//------------------------------------------------------------------------------
++	template <typename T, typename K>
++	std::string static find_value_in_table( const T& table, const K& key )
++	{
++		std::string res = "?";
++		for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] );
++			  ++i ) {
++			if ( table[i].key == key ) {
++				res = table[i].str;
++				break;
++			}
++		}
++
++		return res;
++	}
++
++	//------------------------------------------------------------------------------
++	template <typename T, typename K>
++	static std::string format_assoc( const T& table, const K& key )
++	{
++		std::string str = find_value_in_table( table, key );
++		if ( str == "?" ) {
++			std::ostringstream oss;
++			oss << str << " (0x" << std::hex << key << ")";
++			str = oss.str();
++		}
++
++		return str;
++	}
++
++	//------------------------------------------------------------------------------
++	template <typename T>
++	static std::string format_assoc( const T& table, const char key )
++	{
++		return format_assoc( table, (const int)key );
++	}
++
++	//------------------------------------------------------------------------------
++	static std::string section_flags( Elf_Xword flags )
++	{
++		std::string ret = "";
++		if ( flags & SHF_WRITE ) {
++			ret += "W";
++		}
++		if ( flags & SHF_ALLOC ) {
++			ret += "A";
++		}
++		if ( flags & SHF_EXECINSTR ) {
++			ret += "X";
++		}
++
++		return ret;
++	}
++
++//------------------------------------------------------------------------------
++#define STR_FUNC_TABLE( name )                                         \
++	template <typename T> static std::string str_##name( const T key ) \
++	{                                                                  \
++		return format_assoc( name##_table, key );                      \
++	}
++
++	STR_FUNC_TABLE( class )
++	STR_FUNC_TABLE( endian )
++	STR_FUNC_TABLE( version )
++	STR_FUNC_TABLE( type )
++	STR_FUNC_TABLE( machine )
++	STR_FUNC_TABLE( section_type )
++	STR_FUNC_TABLE( segment_type )
++	STR_FUNC_TABLE( segment_flag )
++	STR_FUNC_TABLE( symbol_bind )
++	STR_FUNC_TABLE( symbol_type )
++	STR_FUNC_TABLE( dynamic_tag )
++
++#undef STR_FUNC_TABLE
++#undef DUMP_DEC_FORMAT
++#undef DUMP_HEX_FORMAT
++#undef DUMP_STR_FORMAT
++}; // class dump
++
++}; // namespace ELFIO
++
++#endif // ELFIO_DUMP_HPP
++
++/*** End of inlined file: elfio_dump.hpp ***/
++
+diff --git a/tests/kt-test-utils/cpp-stub/stub.h b/tests/kt-test-utils/cpp-stub/stub.h
+new file mode 100644
+index 0000000..c5f2f53
+--- /dev/null
++++ b/tests/kt-test-utils/cpp-stub/stub.h
+@@ -0,0 +1,360 @@
++#ifndef __STUB_H__
++#define __STUB_H__
++
++#ifdef _WIN32
++//windows
++#include <windows.h>
++#include <processthreadsapi.h>
++#else
++//linux
++#include <unistd.h>
++#include <bits/stdint-uintn.h>
++#include <sys/mman.h>
++#endif
++//c
++#include <cstddef>
++#include <cstring>
++//c++
++#include <map>
++
++
++#define ADDR(CLASS_NAME,MEMBER_NAME) (&CLASS_NAME::MEMBER_NAME)
++
++/**********************************************************
++                  replace function
++**********************************************************/
++#ifdef _WIN32
++#define CACHEFLUSH(addr, size) FlushInstructionCache(GetCurrentProcess(), addr, size)
++#else
++#define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size)
++#endif
++
++#if defined(__aarch64__) || defined(_M_ARM64)
++    #define CODESIZE 16U
++    #define CODESIZE_MIN 16U
++    #define CODESIZE_MAX CODESIZE
++    // ldr x9, +8
++    // br x9
++    // addr
++    #define REPLACE_FAR(t, fn, fn_stub)\
++        ((uint32_t*)fn)[0] = 0x58000040 | 9;\
++        ((uint32_t*)fn)[1] = 0xd61f0120 | (9 << 5);\
++        *(long long *)(fn + 8) = (long long )fn_stub;\
++        CACHEFLUSH((char *)fn, CODESIZE);
++    #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub)
++#elif defined(__arm__) || defined(_M_ARM)
++    #define CODESIZE 8U
++    #define CODESIZE_MIN 8U
++    #define CODESIZE_MAX CODESIZE
++    // ldr pc, [pc, #-4]
++    #define REPLACE_FAR(t, fn, fn_stub)\
++        ((uint32_t*)fn)[0] = 0xe51ff004;\
++        ((uint32_t*)fn)[1] = (uint32_t)fn_stub;\
++        CACHEFLUSH((char *)fn, CODESIZE);
++    #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub)
++#elif defined(__mips64)
++    #define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size)
++    #define CODESIZE 80U
++    #define CODESIZE_MIN 80U
++    #define CODESIZE_MAX CODESIZE
++    //mips没有PC指针,所以需要手动入栈出栈
++    //120000ce0:  67bdffe0    daddiu  sp, sp, -32  //入栈
++    //120000ce4:  ffbf0018    sd  ra, 24(sp)
++    //120000ce8:  ffbe0010    sd  s8, 16(sp)
++    //120000cec:  ffbc0008    sd  gp, 8(sp)
++    //120000cf0:  03a0f025    move    s8, sp
++
++    //120000d2c:  03c0e825    move    sp, s8  //出栈
++    //120000d30:  dfbf0018    ld  ra, 24(sp)
++    //120000d34:  dfbe0010    ld  s8, 16(sp)
++    //120000d38:  dfbc0008    ld  gp, 8(sp)
++    //120000d3c:  67bd0020    daddiu  sp, sp, 32
++    //120000d40:  03e00008    jr  ra
++
++    #define REPLACE_FAR(t, fn, fn_stub)\
++        ((uint32_t *)fn)[0] = 0x67bdffe0;\
++        ((uint32_t *)fn)[1] = 0xffbf0018;\
++        ((uint32_t *)fn)[2] = 0xffbe0010;\
++        ((uint32_t *)fn)[3] = 0xffbc0008;\
++        ((uint32_t *)fn)[4] = 0x03a0f025;\
++        *(uint16_t *)(fn + 20) = (long long)fn_stub >> 32;\
++        *(fn + 22) = 0x19;\
++        *(fn + 23) = 0x24;\
++        ((uint32_t *)fn)[6] = 0x0019cc38;\
++        *(uint16_t *)(fn + 28) = (long long)fn_stub >> 16;\
++        *(fn + 30) = 0x39;\
++        *(fn + 31) = 0x37;\
++        ((uint32_t *)fn)[8] = 0x0019cc38;\
++        *(uint16_t *)(fn + 36) = (long long)fn_stub;\
++        *(fn + 38) = 0x39;\
++        *(fn + 39) = 0x37;\
++        ((uint32_t *)fn)[10] = 0x0320f809;\
++        ((uint32_t *)fn)[11] = 0x00000000;\
++        ((uint32_t *)fn)[12] = 0x00000000;\
++        ((uint32_t *)fn)[13] = 0x03c0e825;\
++        ((uint32_t *)fn)[14] = 0xdfbf0018;\
++        ((uint32_t *)fn)[15] = 0xdfbe0010;\
++        ((uint32_t *)fn)[16] = 0xdfbc0008;\
++        ((uint32_t *)fn)[17] = 0x67bd0020;\
++        ((uint32_t *)fn)[18] = 0x03e00008;\
++        ((uint32_t *)fn)[19] = 0x00000000;\
++        CACHEFLUSH((char *)fn, CODESIZE);
++    #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub)
++#elif defined(__thumb__) || defined(_M_THUMB)
++    #error "Thumb is not supported"
++#else //__i386__ _x86_64__
++    #define CODESIZE 13U
++    #define CODESIZE_MIN 5U
++    #define CODESIZE_MAX CODESIZE
++    //13 byte(jmp m16:64)
++    //movabs $0x102030405060708,%r11
++    //jmpq   *%r11
++    static void REPLACE_FAR(void *t, char *fn, char *fn_stub)
++    {
++        *fn = 0x49;
++        *(fn + 1) = 0xbb;
++        *(long long *)(fn + 2) = (long long)fn_stub;
++        *(fn + 10) = 0x41;
++        *(fn + 11) = 0xff;
++        *(fn + 12) = 0xe3;
++        CACHEFLUSH((char *)fn, CODESIZE);
++    }
++    //5 byte(jmp rel32)
++    #define REPLACE_NEAR(t, fn, fn_stub)\
++        *fn = 0xE9;\
++        *(int *)(fn + 1) = (int)(fn_stub - fn - CODESIZE_MIN);\
++        CACHEFLUSH((char *)fn, CODESIZE);
++#endif
++
++struct func_stub
++{
++    char *fn;
++    unsigned char code_buf[CODESIZE];
++    bool far_jmp;
++};
++
++class Stub
++{
++public:
++    Stub()
++    {
++#ifdef _WIN32
++        SYSTEM_INFO sys_info;
++        GetSystemInfo(&sys_info);
++        m_pagesize = sys_info.dwPageSize;
++#else
++        m_pagesize = sysconf(_SC_PAGE_SIZE);
++#endif
++
++        if (m_pagesize < 0)
++        {
++            m_pagesize = 4096;
++        }
++    }
++    ~Stub()
++    {
++        clear();
++    }
++
++    virtual void clear()
++    {
++        std::map<char*,func_stub*>::iterator iter;
++        struct func_stub *pstub;
++        for(iter=m_result.begin(); iter != m_result.end(); iter++)
++        {
++            pstub = iter->second;
++#ifdef _WIN32
++            DWORD lpflOldProtect;
++            if(0 != VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
++#else
++            if (0 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC))
++#endif
++            {
++
++                if(pstub->far_jmp)
++                {
++                    std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX);
++                }
++                else
++                {
++                    std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN);
++                }
++
++#ifdef _WIN32
++                VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect);
++#else
++                CACHEFLUSH(pstub->fn,CODESIZE);
++                mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC);
++#endif
++            }
++
++            iter->second  = NULL;
++            delete pstub;
++        }
++
++        m_result.clear();
++        return;
++    }
++    template<typename T,typename S>
++    bool set(T addr, S addr_stub)
++    {
++        char * fn;
++        char * fn_stub;
++        fn = addrof(addr);
++        fn_stub = addrof(addr_stub);
++        struct func_stub *pstub;
++        std::map<char*,func_stub*>::iterator iter = m_result.find(fn);
++
++        if (iter == m_result.end())
++        {
++            pstub = new func_stub;
++            //start
++            pstub->fn = fn;
++
++            if(distanceof(fn, fn_stub))
++            {
++                pstub->far_jmp = true;
++                std::memcpy(pstub->code_buf, fn, CODESIZE_MAX);
++            }
++            else
++            {
++                pstub->far_jmp = false;
++                std::memcpy(pstub->code_buf, fn, CODESIZE_MIN);
++            }
++        }
++        else {
++            pstub = iter->second;
++            pstub->far_jmp = distanceof(fn, fn_stub);
++        }
++
++
++
++#ifdef _WIN32
++        DWORD lpflOldProtect;
++        if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
++#else
++        if (-1 == mprotect(pageof(pstub->fn), static_cast<size_t>(m_pagesize * 2), PROT_READ | PROT_WRITE | PROT_EXEC))
++#endif
++        {
++            throw("stub set memory protect to w+r+x faild");
++            return  false;
++        }
++
++        if(pstub->far_jmp)
++        {
++            REPLACE_FAR(this, fn, fn_stub);
++        }
++        else
++        {
++            REPLACE_NEAR(this, fn, fn_stub);
++        }
++
++
++#ifdef _WIN32
++        if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect))
++#else
++        if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC))
++#endif
++        {
++            throw("stub set memory protect to r+x failed");
++            return false;
++        }
++        m_result.insert(std::pair<char*,func_stub*>(fn,pstub));
++        return true;
++    }
++
++    template<typename T>
++    bool reset(T addr)
++    {
++        char * fn;
++        fn = addrof(addr);
++
++        std::map<char*,func_stub*>::iterator iter = m_result.find(fn);
++
++        if (iter == m_result.end())
++        {
++            return true;
++        }
++        struct func_stub *pstub;
++        pstub = iter->second;
++
++#ifdef _WIN32
++        DWORD lpflOldProtect;
++        if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
++#else
++        if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC))
++#endif
++        {
++            throw("stub reset memory protect to w+r+x faild");
++            return false;
++        }
++
++        if(pstub->far_jmp)
++        {
++            std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX);
++        }
++        else
++        {
++            std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN);
++        }
++
++#ifdef _WIN32
++        if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect))
++#else
++        CACHEFLUSH(pstub->fn,CODESIZE);
++        if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC))
++#endif
++        {
++            throw("stub reset memory protect to r+x failed");
++            return false;
++        }
++
++        m_result.erase(iter);
++        delete pstub;
++
++        return true;
++    }
++protected:
++    char *pageof(char* addr)
++    {
++#ifdef _WIN32
++        return (char *)((unsigned long long)addr & ~(m_pagesize - 1));
++#else
++        return (char *)((unsigned long)addr & ~(m_pagesize - 1));
++#endif
++    }
++
++    template<typename T>
++    char* addrof(T addr)
++    {
++        union
++        {
++          T _s;
++          char* _d;
++        }ut;
++        ut._s = addr;
++        return ut._d;
++    }
++
++    bool distanceof(char* addr, char* addr_stub)
++    {
++        std::ptrdiff_t diff = addr_stub >= addr ? addr_stub - addr : addr - addr_stub;
++        if((sizeof(addr) > 4) && (((diff >> 31) - 1) > 0))
++        {
++            return true;
++        }
++        return false;
++    }
++
++protected:
++#ifdef _WIN32
++    //LLP64
++    long long m_pagesize;
++#else
++    //LP64
++    long m_pagesize;
++#endif
++    std::map<char*, func_stub*> m_result;
++};
++
++#endif
+diff --git a/tests/unit_test_biodeviceinfo/CMakeLists.txt b/tests/unit_test_biodeviceinfo/CMakeLists.txt
+new file mode 100644
+index 0000000..84c6f99
+--- /dev/null
++++ b/tests/unit_test_biodeviceinfo/CMakeLists.txt
+@@ -0,0 +1,58 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../uniauth-backend/src/biodeviceinfo.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../uniauth-backend/src/biodeviceinfo.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_biodeviceinfo ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_biodeviceinfo
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_biodeviceinfo
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_biodeviceinfo/main.cpp b/tests/unit_test_biodeviceinfo/main.cpp
+new file mode 100644
+index 0000000..b4a6998
+--- /dev/null
++++ b/tests/unit_test_biodeviceinfo/main.cpp
+@@ -0,0 +1,49 @@
++#include <gtest/gtest.h>
++#include "../../uniauth-backend/src/biodeviceinfo.h"
++#include <QByteArray>
++#include <QDataStream>
++ 
++// gtest 测试用例
++TEST(BioDeviceInfoTest, SerializationAndDeserialization) {
++    registerCustomTypes();
++
++    DeviceInfo original;
++    original.device_id = 1;
++    original.device_shortname = "TestDevice";
++    original.device_fullname = "Test Device Full Name";
++    original.driver_enable = 1;
++    original.device_available = 1;
++    original.biotype = BIOTYPE_FINGERPRINT;
++    original.stotype = 0;
++    original.eigtype = 0;
++    original.vertype = 0;
++    original.idtype = 0;
++    original.bustype = 0;
++    original.dev_status = 0;
++    original.ops_status = 0;
++ 
++    QDBusArgument argument;
++    argument<<original;
++
++    DeviceInfo deserialized;
++    argument >> deserialized;
++ 
++    EXPECT_EQ(original.device_id, deserialized.device_id);
++    EXPECT_EQ(original.device_shortname, deserialized.device_shortname);
++    EXPECT_EQ(original.device_fullname, deserialized.device_fullname);
++    EXPECT_EQ(original.driver_enable, deserialized.driver_enable);
++    EXPECT_EQ(original.device_available, deserialized.device_available);
++    EXPECT_EQ(original.biotype, deserialized.biotype);
++    EXPECT_EQ(original.stotype, deserialized.stotype);
++    EXPECT_EQ(original.eigtype, deserialized.eigtype);
++    EXPECT_EQ(original.vertype, deserialized.vertype);
++    EXPECT_EQ(original.idtype, deserialized.idtype);
++    EXPECT_EQ(original.bustype, deserialized.bustype);
++    EXPECT_EQ(original.dev_status, deserialized.dev_status);
++    EXPECT_EQ(original.ops_status, deserialized.ops_status);
++}
++ 
++int main(int argc, char **argv) {
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_biodevices/CMakeLists.txt b/tests/unit_test_biodevices/CMakeLists.txt
+new file mode 100644
+index 0000000..f13d84a
+--- /dev/null
++++ b/tests/unit_test_biodevices/CMakeLists.txt
+@@ -0,0 +1,76 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(PkgConfig REQUIRED)
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets Svg REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++find_package(OpenCV REQUIRED)
++
++pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0)
++pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    main.cpp
++    ../../bioauth/src/uniauthservice.cpp
++    ../../bioauth/src/biotypes.cpp
++    ../../bioauth/src/giodbus.cpp
++    ../../bioauth/src/bioauth.cpp
++    ../../bioauth/src/biodevices.cpp
++    ../../bioauth/src/loginoptionswidget.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../bioauth/include/uniauthservice.h
++    ../../bioauth/include/bioauth.h
++    ../../bioauth/include/biodevices.h
++    ../../bioauth/include/loginoptionswidget.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ../../bioauth/include
++    ../../common
++    ${GIOUNIX2_INCLUDE_DIRS}
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_biodevices ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_biodevices
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++    Qt5::Svg
++    ${OpenCV_LIBS}
++    ${GIOUNIX2_LIBRARIES}
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_biodevices
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_biodevices/main.cpp b/tests/unit_test_biodevices/main.cpp
+new file mode 100644
+index 0000000..44e1d47
+--- /dev/null
++++ b/tests/unit_test_biodevices/main.cpp
+@@ -0,0 +1,114 @@
++#include <gtest/gtest.h>
++#include <QApplication>
++#include <QDBusMessage>
++#include <QDBusPendingCall>
++#include <QDBusPendingCallWatcher>
++#include <QDebug>
++#include "../../bioauth/include/biodevices.h" // 假设这个头文件存在,并包含了BioAuth类的声明
++
++TEST(BioDevicesTest, init)
++{
++   BioDevices devices;
++   
++   EXPECT_EQ(devices.count(),0);
++
++   devices.setUId(1000);
++   devices.getAllDevices();
++   devices.getUserDevices(1000);
++   devices.getDevices(0);
++   devices.getDefaultDevice(1000);
++   devices.getDefaultDevice(1000,0);
++
++   devices.GetLastDevice("kylin");
++   devices.SetLastDevice("kylin",100);
++   devices.SetLastDevice("kylin",-1);
++   devices.SetLastDevice("testx",100);
++   devices.findDevice("testDevice");
++   devices.findDevice(100);
++   devices.getFirstDevice(1000);
++   devices.GetDevList();
++   devices.getFeatureCount(1000,0,-1);
++   devices.bioTypeToString_tr(0);
++   devices.bioTypeToString_tr(1);
++   devices.bioTypeToString_tr(2);
++   devices.bioTypeToString_tr(3);
++   devices.bioTypeToString_tr(4);
++   devices.bioTypeToString_tr(5);
++   devices.bioTypeToString_tr(6);
++   devices.bioTypeToString_tr(7);
++   devices.bioTypeToString_tr(8);
++   devices.setIsShowHotPlug(true);
++   devices.setIsShowHotPlug(false);
++   devices.GetUserDevFeatureCount(1000,100);
++   devices.GetUserDevCount(1000);
++   devices.GetUserFeatures(1000);
++   devices.getUseFirstDevice();
++   devices.getFailedTimes(); 
++   devices.GetHiddenSwitchButton();
++   devices.GetQRCodeEnable();
++   devices.GetBioAuthEnable();
++   devices.getAllDefDevices();
++   devices.UpdateStatus(100);
++   devices.UpdateStatus(-1);
++   devices.GetBioAuthEnable(1000);
++   devices.GetDirveIsIdle(100);
++   devices.recordAuthDrive("test",100,true);
++   devices.recordAuthDrive("test",100,false);
++    
++   devices.onUSBDeviceHotPlug(10,-1,10);
++   devices.onUSBDeviceHotPlug(10,1,10);
++   
++   devices.m_uniAuthService = nullptr;
++
++   devices.setUId(1000);
++   devices.getAllDevices();
++   devices.getUserDevices(1000);
++   devices.getDevices(0);
++   devices.getDefaultDevice(1000);
++   devices.getDefaultDevice(1000,0);
++
++   devices.GetLastDevice("kylin");
++   devices.SetLastDevice("kylin",100);
++   devices.SetLastDevice("kylin",-1);
++   devices.findDevice("testDevice");
++   devices.findDevice(100);
++   devices.getFirstDevice(1000);
++   devices.GetDevList();
++   devices.getFeatureCount(1000,0,-1);
++   devices.bioTypeToString_tr(0);
++   devices.bioTypeToString_tr(1);
++   devices.bioTypeToString_tr(2);
++   devices.bioTypeToString_tr(3);
++   devices.bioTypeToString_tr(4);
++   devices.bioTypeToString_tr(5);
++   devices.bioTypeToString_tr(6);
++   devices.bioTypeToString_tr(7);
++   devices.bioTypeToString_tr(8);
++   devices.setIsShowHotPlug(true);
++   devices.setIsShowHotPlug(false);
++   devices.GetUserDevFeatureCount(1000,100);
++   devices.GetUserDevCount(1000);
++   devices.GetUserFeatures(1000);
++   devices.getUseFirstDevice();
++   devices.getFailedTimes();
++   devices.GetHiddenSwitchButton();
++   devices.GetQRCodeEnable();
++   devices.GetBioAuthEnable();
++   devices.getAllDefDevices();
++   devices.UpdateStatus(100);
++   devices.UpdateStatus(-1);
++   devices.GetBioAuthEnable(1000);
++   devices.GetDirveIsIdle(100);
++   devices.recordAuthDrive("test",100,true);
++   devices.recordAuthDrive("test",100,false);
++
++   devices.onUSBDeviceHotPlug(10,-1,10);
++   devices.onUSBDeviceHotPlug(10,1,10);
++}
++  
++// 创建一个全局的QApplication对象,因为Qt测试通常需要一个事件循环
++int main(int argc, char **argv) {
++    QApplication a(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_common/CMakeLists.txt b/tests/unit_test_common/CMakeLists.txt
+new file mode 100644
+index 0000000..85efe1e
+--- /dev/null
++++ b/tests/unit_test_common/CMakeLists.txt
+@@ -0,0 +1,60 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../common/generic.cpp
++    main.cpp
++    unit_test_common.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../common/generic.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_common ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_common
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_common
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_common/main.cpp b/tests/unit_test_common/main.cpp
+new file mode 100644
+index 0000000..37b3fbf
+--- /dev/null
++++ b/tests/unit_test_common/main.cpp
+@@ -0,0 +1,12 @@
++#include <gtest/gtest.h>
++#include <QGuiApplication>
++
++
++int main(int argc, char **argv)
++{
++    QGuiApplication a(argc, argv);
++    testing::InitGoogleTest(&argc, argv);
++
++    return RUN_ALL_TESTS();
++}
++
+diff --git a/tests/unit_test_common/unit_test_common.cpp b/tests/unit_test_common/unit_test_common.cpp
+new file mode 100644
+index 0000000..743d0bc
+--- /dev/null
++++ b/tests/unit_test_common/unit_test_common.cpp
+@@ -0,0 +1,29 @@
++#include <gtest/gtest.h>
++#include <gtest/gtest-death-test.h>
++#include <QString>
++#include <QDebug>
++#include "../../common/generic.h"
++
++#include "stubext.h"
++using namespace stub_ext;
++
++bool enableDebug = true;
++QString logPrefix = "[test]:";
++
++class GenericTest : public testing::Test
++{
++protected:
++
++};
++
++TEST_F(GenericTest, outputMessage)
++{
++    qInstallMessageHandler(outputMessage);
++    qDebug()<<"test1";
++    qWarning()<<"test2";
++    qInfo()<<"test3"; 
++    qCritical()<<"test4";
++
++    enableDebug = false;
++    qDebug()<<"test5";    
++}
+diff --git a/tests/unit_test_giodbus/CMakeLists.txt b/tests/unit_test_giodbus/CMakeLists.txt
+new file mode 100644
+index 0000000..6c37b75
+--- /dev/null
++++ b/tests/unit_test_giodbus/CMakeLists.txt
+@@ -0,0 +1,65 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0)
++pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../bioauth/src/giodbus.cpp
++    unit_test_giodbus.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../bioauth/include/giodbus.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ${CMAKE_CURRENT_SOURCE_DIR}/../../bioauth/include/
++    ${GIOUNIX2_INCLUDE_DIRS}
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_giodbus ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_giodbus
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_giodbus
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++     ${GIOUNIX2_LIBRARIES}
++)
++
+diff --git a/tests/unit_test_giodbus/main.cpp b/tests/unit_test_giodbus/main.cpp
+new file mode 100644
+index 0000000..37b3fbf
+--- /dev/null
++++ b/tests/unit_test_giodbus/main.cpp
+@@ -0,0 +1,12 @@
++#include <gtest/gtest.h>
++#include <QGuiApplication>
++
++
++int main(int argc, char **argv)
++{
++    QGuiApplication a(argc, argv);
++    testing::InitGoogleTest(&argc, argv);
++
++    return RUN_ALL_TESTS();
++}
++
+diff --git a/tests/unit_test_giodbus/unit_test_giodbus.cpp b/tests/unit_test_giodbus/unit_test_giodbus.cpp
+new file mode 100644
+index 0000000..7875c1c
+--- /dev/null
++++ b/tests/unit_test_giodbus/unit_test_giodbus.cpp
+@@ -0,0 +1,19 @@
++#include <gtest/gtest.h>
++#include <gtest/gtest-death-test.h>
++
++#include "../../bioauth/include/giodbus.h"
++
++#include "stubext.h"
++using namespace stub_ext;
++
++class FreedesktopHelperTest : public testing::Test
++{
++protected:
++
++};
++
++TEST_F(FreedesktopHelperTest, get_server_gvariant_stdout)
++{
++    int value = get_server_gvariant_stdout(-1); 
++    ASSERT_EQ(value, -1);
++}
+diff --git a/tests/unit_test_kalabel/CMakeLists.txt b/tests/unit_test_kalabel/CMakeLists.txt
+new file mode 100644
+index 0000000..43b9cb8
+--- /dev/null
++++ b/tests/unit_test_kalabel/CMakeLists.txt
+@@ -0,0 +1,59 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/kalabel.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/kalabel.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_kalabel ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_kalabel
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_kalabel
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_kalabel/main.cpp b/tests/unit_test_kalabel/main.cpp
+new file mode 100644
+index 0000000..2794782
+--- /dev/null
++++ b/tests/unit_test_kalabel/main.cpp
+@@ -0,0 +1,67 @@
++#include <gtest/gtest.h>
++#include "../../polkit-agent/src/kalabel.h"
++#include <QFont>
++#include <QFontMetrics>
++#include <QApplication>
++ 
++// 辅助函数,用于创建QFontMetrics对象,避免在测试中重复代码
++QFontMetrics createFontMetrics(const QFont& font) {
++    return QFontMetrics(font);
++}
++ 
++// 测试getElidedText方法是否正确地省略了文本
++TEST(KALabelTest, GetElidedText_ShouldElideTextIfWidthIsExceeded) {
++    // 创建一个QFont对象,并设置其属性(这里使用默认属性)
++    QFont font;
++    QFontMetrics fontMetrics = createFontMetrics(font);
++ 
++    // 设置测试字符串和宽度
++    QString testString = "This is a very long text that needs to be elided.";
++    int width = fontMetrics.width("This is a short text."); // 假设这个宽度是合适的测试宽度
++ 
++    // 创建KALabel对象(仅为了访问其getElidedText方法)
++    KALabel kalabel;
++ 
++    // 调用getElidedText方法
++    QString elidedText = kalabel.getElidedText(font, width, testString);
++ 
++    // 检查文本是否被省略
++    EXPECT_TRUE(elidedText.endsWith("..."));
++    EXPECT_LT(fontMetrics.width(elidedText), width);
++}
++ 
++// 测试getElidedText方法在没有超过宽度时是否返回原始文本
++TEST(KALabelTest, GetElidedText_ShouldNotElideTextIfWidthIsNotExceeded) {
++    // 创建一个QFont对象,并设置其属性(这里使用默认属性)
++    QFont font;
++    QFontMetrics fontMetrics = createFontMetrics(font);
++ 
++    // 设置测试字符串和宽度(确保宽度足够大以容纳整个字符串)
++    QString testString = "Short text";
++    int width = fontMetrics.width(testString) + 10; // 加一些额外的宽度以确保不会省略
++ 
++    // 创建KALabel对象(仅为了访问其getElidedText方法)
++    KALabel kalabel;
++ 
++    // 调用getElidedText方法
++    QString elidedText = kalabel.getElidedText(font, width, testString);
++ 
++    // 检查文本是否未被省略
++    EXPECT_EQ(elidedText, testString);
++}
++ 
++TEST(KALabelTest, ShowTest) {
++    KALabel kalabel;
++    KALabel kalabel1("test");
++    kalabel1.setText("test1");
++    kalabel1.setFixedWidth(80);
++    kalabel1.paintEvent(nullptr);
++    kalabel1.setText("long long long long long test text");
++    kalabel1.paintEvent(nullptr);
++}
++
++int main(int argc, char **argv) {
++    QApplication a(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_keywatcher/CMakeLists.txt b/tests/unit_test_keywatcher/CMakeLists.txt
+new file mode 100644
+index 0000000..5439f7f
+--- /dev/null
++++ b/tests/unit_test_keywatcher/CMakeLists.txt
+@@ -0,0 +1,60 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets Test REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../bioauth-bin/src/keywatcher.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../bioauth-bin/src/keywatcher.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_keywatcher ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_keywatcher
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++    Qt5::Test
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_keywatcher
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_keywatcher/main.cpp b/tests/unit_test_keywatcher/main.cpp
+new file mode 100644
+index 0000000..652b6d7
+--- /dev/null
++++ b/tests/unit_test_keywatcher/main.cpp
+@@ -0,0 +1,50 @@
++#include <gtest/gtest.h>
++#include <QCoreApplication>
++#include <QSignalSpy>
++#include "../../bioauth-bin/src/keywatcher.h"
++ 
++class KeyWatcherTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        app = new QCoreApplication(argc, argv);
++        watcher = new KeyWatcher(nullptr);
++    }
++ 
++    void TearDown() override {
++        delete watcher;
++        delete qApp;
++    }
++ 
++    QCoreApplication* app;
++    KeyWatcher* watcher;
++    int argc = 0;
++    char** argv = nullptr;
++};
++ 
++TEST_F(KeyWatcherTest, ConstructionAndDestruction) {
++    // Verify that the KeyWatcher object can be constructed and destroyed without crashing.
++    EXPECT_TRUE(watcher != nullptr);
++}
++ 
++TEST_F(KeyWatcherTest, EmitExitSignal) {
++    // This test is tricky because it depends on terminal I/O.
++    // We can use a signal spy to detect the exit signal.
++    //QSignalSpy spy(watcher, &KeyWatcher::exit);
++ 
++    // Normally, we would need to run the KeyWatcher thread and simulate input.
++    // However, for simplicity, we will just call stop() which should trigger the cleanup code.
++    //watcher->stop();
++ 
++    // Note: This is not a complete test of the run() method, just a check for signal emission.
++    // A proper test would require simulating terminal input and output.
++    //EXPECT_EQ(spy.count(), 1);
++}
++ 
++// Additional tests could be added here to test other parts of the KeyWatcher class.
++// For example, testing the behavior of the run() method with different inputs would require
++// setting up a mock terminal or using some form of input redirection.
++ 
++int main(int argc, char **argv) {
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_loginoptionswidget/CMakeLists.txt b/tests/unit_test_loginoptionswidget/CMakeLists.txt
+new file mode 100644
+index 0000000..eb5bf15
+--- /dev/null
++++ b/tests/unit_test_loginoptionswidget/CMakeLists.txt
+@@ -0,0 +1,77 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(PkgConfig REQUIRED)
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets Svg REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++find_package(OpenCV REQUIRED)
++
++pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0)
++pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++qt5_add_resources(polkit_SRCS ../../polkit-agent/assets.qrc)
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    main.cpp
++    ../../bioauth/src/uniauthservice.cpp
++    ../../bioauth/src/biotypes.cpp
++    ../../bioauth/src/giodbus.cpp
++    ../../bioauth/src/bioauth.cpp
++    ../../bioauth/src/biodevices.cpp
++    ../../bioauth/src/loginoptionswidget.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../bioauth/include/uniauthservice.h
++    ../../bioauth/include/bioauth.h
++    ../../bioauth/include/biodevices.h
++    ../../bioauth/include/loginoptionswidget.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ../../bioauth/include
++    ../../common
++    ${GIOUNIX2_INCLUDE_DIRS}
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_loginoptionswidget ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_loginoptionswidget
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++    Qt5::Svg
++    ${OpenCV_LIBS}
++    ${GIOUNIX2_LIBRARIES}
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_loginoptionswidget
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_loginoptionswidget/main.cpp b/tests/unit_test_loginoptionswidget/main.cpp
+new file mode 100644
+index 0000000..3fed4d7
+--- /dev/null
++++ b/tests/unit_test_loginoptionswidget/main.cpp
+@@ -0,0 +1,355 @@
++#include <gtest/gtest.h>
++#include <QApplication>
++#include <QIcon>
++#include <QDBusMessage>
++#include <QDBusPendingCall>
++#include <QDBusPendingCallWatcher>
++#include <QDebug>
++#include "../../bioauth/include/loginoptionswidget.h" // 假设这个头文件存在,并包含了BioAuth类的声明
++
++TEST(LoginOptionsWidgetTest, init)
++{
++    LoginOptionsWidget loginWidget;
++    
++    EXPECT_EQ(loginWidget.getLoginOptCount(),0);
++    EXPECT_EQ(loginWidget.convertDeviceType(0),0);
++
++    int nLoginOptType,nDrvId;
++    loginWidget.getCurLoginOpt(nLoginOptType,nDrvId);
++    loginWidget.getFirstDevInfo();
++    loginWidget.updateUIStatus(false);
++    loginWidget.updateUIStatus(true);
++    loginWidget.updateUkeyUIStatus(0);
++    loginWidget.updateUkeyUIStatus(1);
++    loginWidget.updateUkeyUIStatus(8);
++    loginWidget.setUser(1000);
++    loginWidget.setCurrentDevice(-1);
++    loginWidget.setCurrentDevice("test");
++    loginWidget.setDeviceDisable(100,false);
++    loginWidget.setDeviceDisable(100,true);
++    loginWidget.isDeviceDisable(false);
++    loginWidget.lockStatusChanged(false);  
++    loginWidget.lockStatusChanged(true);  
++   
++    loginWidget.readDevicesInfo();
++    loginWidget.onIdentifyComplete(1000,true,0);
++    loginWidget.onIdentifyComplete(1000,false,0);
++    loginWidget.onIdentifyComplete(-1,true,0);
++    loginWidget.onAuthFinished();
++    loginWidget.onStatusChanged(1000,"test");
++    loginWidget.onFrameWritten(1000);
++    loginWidget.onUSBDeviceCountChange(0);
++    loginWidget.onUSBDeviceCountChange(1);
++    loginWidget.onOptionSelected(-1);
++    loginWidget.onOptionSelected(0);
++    loginWidget.onOptionSelected(1);
++    loginWidget.setQRCodeMsg("");
++    loginWidget.setQRCodeMsg("test");
++ 
++    EXPECT_EQ(loginWidget.GetDefaultDevice(1000),""); 
++    EXPECT_EQ(loginWidget.GetDefaultDevice(1000,0),"");
++
++    loginWidget.startAuth(nullptr,1000);
++    loginWidget.stopAuth();
++    loginWidget.SetExtraInfo("test1","test2");
++    EXPECT_EQ(loginWidget.getHasUkeyOptions(),false);
++    loginWidget.setSelectedPassword();
++    loginWidget.setAllDeviceDisable(true);
++    loginWidget.setAllDeviceDisable(false);
++
++    loginWidget.notifyOptionsChange(-1);
++    loginWidget.notifyOptionsChange(0);
++    loginWidget.notifyOptionsChange(1);
++    loginWidget.optionSelected(LOGINOPT_TYPE_GENERAL_UKEY,nullptr);
++    QImage image;
++    loginWidget.updateImage(image);
++    loginWidget.authComplete(1000,-1,-1);
++    loginWidget.updateAuthMsg("test");
++    loginWidget.updateWndSize(0,100);
++    loginWidget.initUI();
++    loginWidget.initConnections();
++    loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_GENERAL_UKEY,1,"LOGINOPT_TYPE_GENERAL_UKEY");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FACE,2,"LOGINOPT_TYPE_FACE");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERPRINT,3,"LOGINOPT_TYPE_FINGERPRINT");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_IRIS,4,"LOGINOPT_TYPE_IRIS");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_VOICEPRINT,5,"LOGINOPT_TYPE_VOICEPRINT");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERVEIN,6,"LOGINOPT_TYPE_FINGERVEIN");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_QRCODE,7,"LOGINOPT_TYPE_QRCODE");
++    loginWidget.onOptionSelected(-1);
++    loginWidget.onOptionSelected(0);
++    loginWidget.onOptionSelected(1);
++    loginWidget.clearOptionButtons();
++    loginWidget.updateOptionButtons();
++    loginWidget.startAuth_();
++    loginWidget.stopAuth();
++    QPixmap pix = QIcon::fromTheme("ukui-loading-0-symbolic").pixmap(24, 24);
++    loginWidget.PixmapToRound(pix,32);
++    QPixmap pix1;
++    loginWidget.PixmapToRound(pix1,32);
++    loginWidget.scaledPixmap(1024,768,"/usr/share/backgrounds/1-warty-final-ubuntukylin.jpg"); 
++    loginWidget.scaledPixmap(1024,768,"/usr/share/backgrounds/test-warty-final-ubuntukylin.jpg"); 
++    loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/images/ukui-loginopt-face.svg"); 
++    loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/images/FingerPrint.gif"); 
++    loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/ukui-biometric.conf"); 
++    loginWidget.updatePixmap();
++
++    loginWidget.drawSymbolicColoredPixmap(pix,"white"); 
++    loginWidget.drawSymbolicColoredPixmap(pix,"blue"); 
++    loginWidget.drawSymbolicColoredPixmap(pix,"gray"); 
++    loginWidget.drawSymbolicColoredPixmap(pix,"black"); 
++    loginWidget.drawSymbolicColoredPixmap(pix,"red"); 
++    
++    QImage img;   
++    QImage img1 = pix1.toImage();
++    loginWidget.setFaceImg(img,1);
++    loginWidget.setFaceImg(img,2);
++    loginWidget.setFaceImg(img,3);
++    loginWidget.setFaceImg(img1,1);
++
++    loginWidget.convertDeviceType(BIOTYPE_FINGERPRINT);
++    loginWidget.convertDeviceType(BIOTYPE_FINGERVEIN);
++    loginWidget.convertDeviceType(BIOTYPE_IRIS);
++    loginWidget.convertDeviceType(BIOTYPE_FACE);
++    loginWidget.convertDeviceType(BIOTYPE_VOICEPRINT);
++    loginWidget.convertDeviceType(UniT_General_Ukey);
++    loginWidget.convertDeviceType(UniT_Advanced_Ukey);
++    loginWidget.convertDeviceType(REMOTE_QRCODE_TYPE);
++    loginWidget.convertDeviceType(-1);
++}
++ 
++TEST(LoginOptionsWidgetTest, noProxy) {
++    LoginOptionsWidget loginWidget;
++    loginWidget.m_biomericProxy = nullptr;
++    loginWidget.SetExtraInfo("test1","test2");
++}
++
++// 模拟startAuth的调用
++TEST(LoginOptionsWidgetTest, startAuth) {
++    DeviceInfoPtr pDeviceInfo = std::make_shared<DeviceInfo>();
++    pDeviceInfo->device_id = 100;
++    pDeviceInfo->device_shortname = "TestDevice";
++    pDeviceInfo->device_fullname = "Test Device Full Name";
++    pDeviceInfo->driver_enable = 1;
++    pDeviceInfo->device_available = 1;
++    pDeviceInfo->biotype = BIOTYPE_FINGERPRINT;
++    pDeviceInfo->stotype = 0;
++    pDeviceInfo->eigtype = 0;
++    pDeviceInfo->vertype = 0;
++    pDeviceInfo->idtype = 0;
++    pDeviceInfo->bustype = 0;
++    pDeviceInfo->dev_status = 0;
++    pDeviceInfo->ops_status = 0;
++
++    LoginOptionsWidget loginWidget;
++    loginWidget.onOptionSelected(-1);
++    loginWidget.onOptionSelected(0);
++    loginWidget.onOptionSelected(1);
++    loginWidget.m_mapDevices[LOGINOPT_TYPE_FINGERPRINT].push_back(pDeviceInfo);
++    loginWidget.setCurrentDevice("TestDevice"); 
++    loginWidget.setCurrentDevice(100); 
++    loginWidget.setCurrentDevice(pDeviceInfo); 
++    loginWidget.startAuth(pDeviceInfo,1000);
++
++    loginWidget.m_isInAuth = true;
++    loginWidget.stopAuth();
++
++    loginWidget.onStatusChanged(100,"this is test");
++}
++
++// 模拟认证完成
++TEST(LoginOptionsWidgetTest, onIdentifyComplete) {
++    LoginOptionsWidget loginWidget;
++    loginWidget.m_isStopped = false;
++
++    loginWidget.onIdentifyComplete(-1,-1,-1);
++    loginWidget.onIdentifyComplete(0,-1,-1);
++    loginWidget.onIdentifyComplete(0,-1,1000);
++    loginWidget.onIdentifyComplete(0,-1,200);
++    loginWidget.onIdentifyComplete(-1,-1,-3);
++}
++
++//模拟device管理
++TEST(LoginOptionsWidgetTest, testAllDevice) {
++    DeviceInfoPtr pDeviceInfo = std::make_shared<DeviceInfo>();
++    pDeviceInfo->device_id = 100;
++    pDeviceInfo->device_shortname = "TestDevice";
++    pDeviceInfo->device_fullname = "Test Device Full Name";
++    pDeviceInfo->driver_enable = 1;
++    pDeviceInfo->device_available = 1;
++    pDeviceInfo->biotype = BIOTYPE_FINGERPRINT;
++    pDeviceInfo->stotype = 0;
++    pDeviceInfo->eigtype = 0;
++    pDeviceInfo->vertype = 0;
++    pDeviceInfo->idtype = 0;
++    pDeviceInfo->bustype = 0;
++    pDeviceInfo->dev_status = 0;
++    pDeviceInfo->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo1 = std::make_shared<DeviceInfo>();
++    pDeviceInfo1->device_id = 101;
++    pDeviceInfo1->device_shortname = "TestDevice1";
++    pDeviceInfo1->device_fullname = "Test Device Full Name";
++    pDeviceInfo1->driver_enable = 1;
++    pDeviceInfo1->device_available = 1;
++    pDeviceInfo1->biotype = BIOTYPE_FINGERVEIN;
++    pDeviceInfo1->stotype = 0;
++    pDeviceInfo1->eigtype = 0;
++    pDeviceInfo1->vertype = 0;
++    pDeviceInfo1->idtype = 0;
++    pDeviceInfo1->bustype = 0;
++    pDeviceInfo1->dev_status = 0;
++    pDeviceInfo1->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo2 = std::make_shared<DeviceInfo>();
++    pDeviceInfo2->device_id = 102;
++    pDeviceInfo2->device_shortname = "TestDevice2";
++    pDeviceInfo2->device_fullname = "Test Device Full Name";
++    pDeviceInfo2->driver_enable = 1;
++    pDeviceInfo2->device_available = 1;
++    pDeviceInfo2->biotype = BIOTYPE_IRIS;
++    pDeviceInfo2->stotype = 0;
++    pDeviceInfo2->eigtype = 0;
++    pDeviceInfo2->vertype = 0;
++    pDeviceInfo2->idtype = 0;
++    pDeviceInfo2->bustype = 0;
++    pDeviceInfo2->dev_status = 0;
++    pDeviceInfo2->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo3 = std::make_shared<DeviceInfo>();
++    pDeviceInfo3->device_id = 103;
++    pDeviceInfo3->device_shortname = "TestDevice3";
++    pDeviceInfo3->device_fullname = "Test Device Full Name";
++    pDeviceInfo3->driver_enable = 1;
++    pDeviceInfo3->device_available = 1;
++    pDeviceInfo3->biotype = BIOTYPE_FACE;
++    pDeviceInfo3->stotype = 0;
++    pDeviceInfo3->eigtype = 0;
++    pDeviceInfo3->vertype = 0;
++    pDeviceInfo3->idtype = 0;   
++    pDeviceInfo3->bustype = 0;
++    pDeviceInfo3->dev_status = 0;
++    pDeviceInfo3->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo4 = std::make_shared<DeviceInfo>();
++    pDeviceInfo4->device_id = 104;
++    pDeviceInfo4->device_shortname = "TestDevice4";
++    pDeviceInfo4->device_fullname = "Test Device Full Name";
++    pDeviceInfo4->driver_enable = 1;
++    pDeviceInfo4->device_available = 1;
++    pDeviceInfo4->biotype = BIOTYPE_VOICEPRINT;
++    pDeviceInfo4->stotype = 0;
++    pDeviceInfo4->eigtype = 0;
++    pDeviceInfo4->vertype = 0;
++    pDeviceInfo4->idtype = 0;
++    pDeviceInfo4->bustype = 0;
++    pDeviceInfo4->dev_status = 0;
++    pDeviceInfo4->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo5 = std::make_shared<DeviceInfo>();
++    pDeviceInfo5->device_id = 105;
++    pDeviceInfo5->device_shortname = "TestDevice5";
++    pDeviceInfo5->device_fullname = "Test Device Full Name";
++    pDeviceInfo5->driver_enable = 1;
++    pDeviceInfo5->device_available = 1;
++    pDeviceInfo5->biotype = 6;
++    pDeviceInfo5->stotype = 0;
++    pDeviceInfo5->eigtype = 0;
++    pDeviceInfo5->vertype = 0;
++    pDeviceInfo5->idtype = 0;
++    pDeviceInfo5->bustype = 0;
++    pDeviceInfo5->dev_status = 0;
++    pDeviceInfo5->ops_status = 0;
++ 
++    DeviceInfoPtr pDeviceInfo6 = std::make_shared<DeviceInfo>();
++    pDeviceInfo6->device_id = 106;
++    pDeviceInfo6->device_shortname = "TestDevice6";
++    pDeviceInfo6->device_fullname = "Test Device Full Name";
++    pDeviceInfo6->driver_enable = 1;
++    pDeviceInfo6->device_available = 1;
++    pDeviceInfo6->biotype = 6;
++    pDeviceInfo6->stotype = 0;
++    pDeviceInfo6->eigtype = 0;
++    pDeviceInfo6->vertype = 0;
++    pDeviceInfo6->idtype = 0;
++    pDeviceInfo6->bustype = 0;
++    pDeviceInfo6->dev_status = 0;
++    pDeviceInfo6->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo7 = std::make_shared<DeviceInfo>();
++    pDeviceInfo7->device_id = 107;
++    pDeviceInfo7->device_shortname = "TestDevice7";
++    pDeviceInfo7->device_fullname = "Test Device Full Name";
++    pDeviceInfo7->driver_enable = 1;
++    pDeviceInfo7->device_available = 1;
++    pDeviceInfo7->biotype = 7;
++    pDeviceInfo7->stotype = 0;
++    pDeviceInfo7->eigtype = 0;
++    pDeviceInfo7->vertype = 0;
++    pDeviceInfo7->idtype = 0;
++    pDeviceInfo7->bustype = 0;
++    pDeviceInfo7->dev_status = 0;
++    pDeviceInfo7->ops_status = 0;
++
++    DeviceInfoPtr pDeviceInfo8 = std::make_shared<DeviceInfo>();
++    pDeviceInfo8->device_id = 108;
++    pDeviceInfo8->device_shortname = "TestDevice8";
++    pDeviceInfo8->device_fullname = "Test Device Full Name";
++    pDeviceInfo8->driver_enable = 1;
++    pDeviceInfo8->device_available = 1;
++    pDeviceInfo8->biotype = 8;
++    pDeviceInfo8->stotype = 0;
++    pDeviceInfo8->eigtype = 0;
++    pDeviceInfo8->vertype = 0;
++    pDeviceInfo8->idtype = 0;
++    pDeviceInfo8->bustype = 0;
++    pDeviceInfo8->dev_status = 0;
++    pDeviceInfo8->ops_status = 0;
++
++    LoginOptionsWidget loginWidget;
++    loginWidget.m_mapDevices[0].push_back(pDeviceInfo); 
++    loginWidget.m_mapDevices[1].push_back(pDeviceInfo1); 
++    loginWidget.m_mapDevices[2].push_back(pDeviceInfo2); 
++    loginWidget.m_mapDevices[3].push_back(pDeviceInfo2); 
++    loginWidget.m_mapDevices[4].push_back(pDeviceInfo4); 
++    loginWidget.m_mapDevices[5].push_back(pDeviceInfo5); 
++    loginWidget.m_mapDevices[6].push_back(pDeviceInfo6); 
++    loginWidget.m_mapDevices[7].push_back(pDeviceInfo7); 
++    loginWidget.m_mapDevices[8].push_back(pDeviceInfo8);
++
++    loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_GENERAL_UKEY,1,"LOGINOPT_TYPE_GENERAL_UKEY");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FACE,2,"LOGINOPT_TYPE_FACE");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERPRINT,3,"LOGINOPT_TYPE_FINGERPRINT");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_IRIS,4,"LOGINOPT_TYPE_IRIS");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_VOICEPRINT,5,"LOGINOPT_TYPE_VOICEPRINT");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERVEIN,6,"LOGINOPT_TYPE_FINGERVEIN");
++    loginWidget.addOptionButton(LOGINOPT_TYPE_QRCODE,7,"LOGINOPT_TYPE_QRCODE");
++
++    loginWidget.setCurrentDevice(100);
++    int nLoginOptType,nDrvId;
++    loginWidget.getCurLoginOpt(nLoginOptType,nDrvId);
++ 
++    loginWidget.getFirstDevInfo();
++    loginWidget.updateOptionButtons();
++    loginWidget.setSelectedPassword();
++    
++    loginWidget.startAuth(pDeviceInfo,1000);
++    loginWidget.startAuth(pDeviceInfo1,1000);
++    loginWidget.startAuth(pDeviceInfo2,1000);
++    loginWidget.startAuth(pDeviceInfo3,1000);
++    loginWidget.startAuth(pDeviceInfo4,1000);
++    loginWidget.startAuth(pDeviceInfo5,1000);
++    loginWidget.startAuth(pDeviceInfo6,1000);
++    loginWidget.startAuth(pDeviceInfo7,1000);
++    loginWidget.startAuth(pDeviceInfo8,1000);
++
++}
++ 
++// 创建一个全局的QApplication对象,因为Qt测试通常需要一个事件循环
++int main(int argc, char **argv) {
++    QApplication a(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_modebutton/CMakeLists.txt b/tests/unit_test_modebutton/CMakeLists.txt
+new file mode 100644
+index 0000000..efc3f21
+--- /dev/null
++++ b/tests/unit_test_modebutton/CMakeLists.txt
+@@ -0,0 +1,63 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++pkg_check_modules(QGS REQUIRED gsettings-qt)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/modeButton.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/modeButton.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ${QGS_INCLUDE_DIRS}
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_modebutton ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_modebutton
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++    ${QGS_LIBRARIES}
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_modebutton
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_modebutton/main.cpp b/tests/unit_test_modebutton/main.cpp
+new file mode 100644
+index 0000000..b4fbf47
+--- /dev/null
++++ b/tests/unit_test_modebutton/main.cpp
+@@ -0,0 +1,94 @@
++#include <gtest/gtest.h>
++#include <QApplication>
++#include <QWidget>
++#include <QPixmap>
++#include "../../polkit-agent/src/modeButton.h"
++
++// Test fixture for ModeButton
++class ModeButtonTest : public ::testing::Test {
++protected:
++};
++
++TEST_F(ModeButtonTest, TestDefaultConstructor) {
++    ModeButton button(nullptr);
++    EXPECT_EQ(button.isShowPwd(), false);
++    EXPECT_EQ(button.size(), QSize(24, 24));
++}
++
++TEST_F(ModeButtonTest, TestIconConstructor) {
++    ModeButton button("testIcon", nullptr);
++    // Since we can't directly assert the icon, we assume the constructor sets up the internal state correctly
++    EXPECT_EQ(button.size(), QSize(24, 24));
++    // Further checks would involve mocking QIcon::fromTheme and verifying interactions
++}
++
++TEST_F(ModeButtonTest, TestShowPasswordToggle) {
++    ModeButton button(nullptr);
++    
++    // Mock QGSettings to return a theme name that is not dark or black
++    button.initStyleTheme();
++    
++    // Initially, pwdShow should be false
++    EXPECT_EQ(button.isShowPwd(), false);
++    
++    // Simulate a click event
++    emit button.clicked();
++    
++    // Now pwdShow should be true
++    EXPECT_EQ(button.isShowPwd(), true);
++    
++    // Simulate another click event
++    emit button.clicked();
++    
++    // Now pwdShow should be false again
++    EXPECT_EQ(button.isShowPwd(), false);
++}
++
++TEST_F(ModeButtonTest, TestHoverEffect) {
++    ModeButton button(nullptr);
++    
++    // Mock QGSettings to return a theme name that is not dark or black
++    button.initStyleTheme();
++    
++    // Simulate entering the hover state
++    QEvent enterEvent(QEvent::Enter);
++    QApplication::sendEvent(&button, &enterEvent);
++    
++    // Verify the icon is set to white (or appropriate hover color)
++    // This would involve checking the internal state or mocking QIcon::pixmap and QPixmap::fromImage
++    // Since we can't directly access the icon, we assume setModeIcon handles it correctly
++    
++    // Simulate leaving the hover state
++    QEvent leaveEvent(QEvent::Leave);
++    QApplication::sendEvent(&button, &leaveEvent);
++    
++    // Verify the icon is set back to gray (or appropriate non-hover color)
++    // Similarly, we assume setModeIcon handles it correctly
++}
++
++TEST_F(ModeButtonTest, TestThemeChange) {
++    ModeButton button(nullptr);
++    
++    button.initStyleTheme();
++    button.setModeIcon(); 
++    
++    button.m_styleSettings->changed("styleName");
++    
++    QPixmap pixmap = QIcon::fromTheme("ukui-eye-display-symbolic").pixmap(24,24);
++    pixmap = button.drawSymbolicColoredPixmap(pixmap, "black");
++    pixmap = button.drawSymbolicColoredPixmap(pixmap, "blue");
++    pixmap = button.drawSymbolicColoredPixmap(pixmap, "gray");
++    pixmap = button.drawSymbolicColoredPixmap(pixmap, "white");
++    pixmap = button.drawSymbolicColoredPixmap(pixmap, "red");
++
++    button.m_strThemeName = "ukui-dark";
++    button.setModeIcon();
++    button.m_strThemeName = "ukui-black";
++    button.setModeIcon();
++}
++
++int main(int argc, char **argv) {
++    QApplication app(argc, argv);;
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_pam_tally/CMakeLists.txt b/tests/unit_test_pam_tally/CMakeLists.txt
+new file mode 100644
+index 0000000..132b68b
+--- /dev/null
++++ b/tests/unit_test_pam_tally/CMakeLists.txt
+@@ -0,0 +1,59 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/pam-tally.c
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/pam-tally.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_pam_tally ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_pam_tally
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_pam_tally
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_pam_tally/main.cpp b/tests/unit_test_pam_tally/main.cpp
+new file mode 100644
+index 0000000..95536cc
+--- /dev/null
++++ b/tests/unit_test_pam_tally/main.cpp
+@@ -0,0 +1,113 @@
++#include <gtest/gtest.h>
++#include "../../polkit-agent/src/pam-tally.h"
++#include <sys/mman.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <cstring>
++#include <cstdio>
++#include <cstdlib>
++#include <ctime>
++
++#define CONFIG_FILE "/usr/share/lightdm/lightdm.conf.d/96-kylin-setting.conf"
++ 
++// 辅助函数,用于模拟配置文件内容
++void write_config_file(const char* content) {
++    FILE* file = fopen(CONFIG_FILE, "w");
++    if (file) {
++        fputs(content, file);
++        fclose(file);
++    } else {
++        perror("Failed to open config file for writing");
++        exit(EXIT_FAILURE);
++    }
++}
++ 
++// 辅助函数,用于清理共享内存
++void cleanup_shm() {
++    char shm_name[128];
++    sprintf(shm_name, "%s_%d", SHM_TALLY, getuid());
++    shm_unlink(shm_name);
++}
++ 
++class PamTallyTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        // 在每个测试用例之前运行
++        cleanup_shm(); // 确保每次测试前清理共享内存
++    }
++ 
++    void TearDown() override {
++        // 在每个测试用例之后运行
++        cleanup_shm(); // 确保每次测试后清理共享内存
++    }
++};
++ 
++TEST_F(PamTallyTest, PamTallyInit) {
++    // 测试pam_tally_init函数
++    write_config_file("open-other-authentication=0\n"); // 确保配置关闭其他认证
++ 
++    // 临时修改/etc/pam.d/common-auth文件以进行测试
++    //const char* auth_file_content = "auth required pam_deny.so deny=3 unlock_time=600 root_unlock_time=1800\n";
++    //FILE* auth_file = fopen("/etc/pam.d/common-auth", "w");
++    //if (auth_file) {
++    //    fputs(auth_file_content, auth_file);
++    //    fclose(auth_file);
++    //} else {
++    //    perror("Failed to open auth file for writing");
++    //    exit(EXIT_FAILURE);
++    //}
++ 
++    int result = pam_tally_init();
++    EXPECT_EQ(result, 1); // 预期初始化成功
++}
++ 
++TEST_F(PamTallyTest, PamTallyIsCanUnlock) {
++    // 测试pam_tally_is_canUnlock函数
++    pam_tally_init(); // 初始化pam_tally并设置解锁时间为600秒
++    pam_tally_add_failed(); // 添加一次失败,不足以达到失败次数上限
++    EXPECT_EQ(pam_tally_is_canUnlock(), 1); // 预期可以解锁,因为失败次数未达到上限
++ 
++    // 添加足够多的失败次数以达到上限,并检查是否可以解锁
++    for (int i = 0; i < 2; ++i) {
++        pam_tally_add_failed();
++    }
++    time_t start_time = time(NULL);
++    EXPECT_EQ(pam_tally_is_canUnlock(), 0); // 预期不能解锁,因为失败次数已达到上限且未过解锁时间
++ 
++    // 等待超过解锁时间后,再次检查是否可以解锁
++    sleep(601); // 假设解锁时间为600秒,这里等待601秒以确保超过解锁时间
++    EXPECT_EQ(pam_tally_is_canUnlock(), 1); // 预期现在可以解锁,因为已经超过解锁时间
++}
++
++TEST_F(PamTallyTest, PamTallyUnlockTime) {
++    // 测试pam_tally_is_canUnlock函数
++    pam_tally_init(); // 初始化pam_tally并设置解锁时间为600秒
++    pam_tally_add_failed(); // 添加一次失败,不足以达到失败次数上限
++
++    int failed_count = 0;
++    int time_left = 0;
++    int deny = 0;
++    int fail_time = 0;
++    int unlock_time = 0;
++   
++    pam_tally_unlock_time_left(1000, &failed_count, &time_left, &deny, &fail_time, &unlock_time); 
++    
++    EXPECT_EQ(failed_count, 0);
++    EXPECT_EQ(time_left, 0);
++    EXPECT_EQ(deny, 0);
++    EXPECT_EQ(fail_time, 0);
++    EXPECT_EQ(unlock_time, 0);
++
++    pam_tally_root_unlock_time_left(&failed_count, &time_left, &deny, &fail_time, &unlock_time);
++
++    EXPECT_EQ(failed_count, 0);
++    EXPECT_EQ(time_left, 0);
++    EXPECT_EQ(deny, 0);
++    EXPECT_EQ(fail_time, 0);
++    EXPECT_EQ(unlock_time, 0);
++}
++ 
++int main(int argc, char **argv) {
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_personalizeddata/CMakeLists.txt b/tests/unit_test_personalizeddata/CMakeLists.txt
+new file mode 100644
+index 0000000..1c425a8
+--- /dev/null
++++ b/tests/unit_test_personalizeddata/CMakeLists.txt
+@@ -0,0 +1,64 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++pkg_check_modules(LIGHTDM-QT5-3 REQUIRED liblightdm-qt5-3)
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../uniauth-backend/src/personalizeddata.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../uniauth-backend/src/personalizeddata.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ${CMAKE_CURRENT_SOURCE_DIR}/../../uniauth-backend/src/
++    ${LIGHTDM-QT5-3_INCLUDE_DIRS}
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_personalizeddata ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_personalizeddata
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_personalizeddata
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++    ${GIOUNIX2_LIBRARIES}
++    -lcrypto
++    ${LIGHTDM-QT5-3_LIBRARIES}
++)
++
+diff --git a/tests/unit_test_personalizeddata/main.cpp b/tests/unit_test_personalizeddata/main.cpp
+new file mode 100644
+index 0000000..fea595a
+--- /dev/null
++++ b/tests/unit_test_personalizeddata/main.cpp
+@@ -0,0 +1,92 @@
++#include <gtest/gtest.h>
++#include <QCoreApplication>
++#include <QFile>
++#include <QJsonObject>
++#include <QJsonDocument>
++#include "../../uniauth-backend/src/personalizeddata.h"
++
++// Global instance for testing
++PersonalizedDataMng* g_personalizedDataMng = nullptr;
++
++// Test case for PersonalizedData
++TEST(PersonalizedDataTest, GetJsonData) {
++    // Create a PersonalizedData instance
++    PersonalizedData pd("testuser");
++
++    // Set some values (using direct access for simplicity in this test)
++    pd.dateType("yyyy-MM-dd");
++    pd.fontSize(12);
++    pd.timeType(24);
++    pd.backgroundPath("/path/to/background");
++    pd.color("#FFFFFF");
++    pd.cursor_size(10);
++    pd.cursor_theme("");
++    pd.scaling_factor(1);
++
++    // Get JSON data
++    QJsonObject json;
++    pd.getJsonData(json);
++
++    // Verify JSON data
++    EXPECT_EQ(json["user"].toString(), "testuser");
++    EXPECT_EQ(json["dateType"].toString(), "yyyy-MM-dd");
++    EXPECT_EQ(json["fontSize"].toInt(), 12);
++    EXPECT_EQ(json["timeType"].toInt(), 24);
++    EXPECT_EQ(json["backgroundPath"].toString(), "/path/to/background");
++    EXPECT_EQ(json["color"].toString(), "#FFFFFF");
++
++    pd.dateType();
++    pd.fontSize();
++    pd.timeType();
++    pd.backgroundPath();
++    pd.color();
++    pd.cursor_size();
++    pd.cursor_theme();
++    pd.scaling_factor();
++    pd.getJsonData();
++
++    pd.fileChanged("");
++}
++
++// Test case for PersonalizedDataMng
++TEST(PersonalizedDataMngTest, GetConfInformation) {
++    // Initialize PersonalizedDataMng with mock dependencies if needed
++    if (!g_personalizedDataMng) {
++        g_personalizedDataMng = new PersonalizedDataMng();
++        // Mock QLightDM::UsersModel and other dependencies if necessary
++    }
++
++    // Add a user to the model (simulating onUserAdded)
++    QString userName = "testuser";
++    PersonalizedData* pd = new PersonalizedData(userName);
++    QJsonObject json;
++    pd->getJsonData(json);
++    json["operation"] = "testoperation";
++    QJsonDocument document;
++    document.setObject(json);
++    QString jsonStr = document.toJson(QJsonDocument::Compact);
++
++    // Emit the conf_changed signal (simulating onUserAdded)
++    emit g_personalizedDataMng->conf_changed(jsonStr);
++
++    // Retrieve configuration information
++    QString confInfo = g_personalizedDataMng->GetConfInformation(userName);
++
++    // Verify configuration information (parse JSON and check values)
++    QJsonDocument confDoc = QJsonDocument::fromJson(confInfo.toUtf8());
++    QJsonObject confJson = confDoc.object();
++
++    EXPECT_EQ(confJson["user"].toString(), userName);
++
++//    EXPECT_EQ(confJson["operation"].toInt(), "testoperation");
++    EXPECT_EQ(confJson["dateType"].toString(), "cn"); // Default value from PersonalizedData
++    // Add more verifications as needed
++
++    g_personalizedDataMng->SetLoginSynInformation("");
++}
++
++int main(int argc, char **argv) {
++    QCoreApplication app(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_rsac/CMakeLists.txt b/tests/unit_test_rsac/CMakeLists.txt
+new file mode 100644
+index 0000000..926ea9f
+--- /dev/null
++++ b/tests/unit_test_rsac/CMakeLists.txt
+@@ -0,0 +1,61 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../uniauth-backend/src/rsac.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../uniauth-backend/src/rsac.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++    ${CMAKE_CURRENT_SOURCE_DIR}/../../uniauth-backend/src/
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_rsac ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_rsac
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_rsac
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++    ${GIOUNIX2_LIBRARIES}
++    -lcrypto
++)
++
+diff --git a/tests/unit_test_rsac/main.cpp b/tests/unit_test_rsac/main.cpp
+new file mode 100644
+index 0000000..11b6bfc
+--- /dev/null
++++ b/tests/unit_test_rsac/main.cpp
+@@ -0,0 +1,104 @@
++#include <gtest/gtest.h>
++#include "../../uniauth-backend/src/rsac.h"
++#include <openssl/rsa.h>
++#include <openssl/pem.h>
++#include <openssl/err.h>
++#include <QByteArray>
++#include <QString>
++#include <iostream>
++#include <QFile>
++ 
++// 辅助函数,用于初始化OpenSSL库
++void InitOpenSSL() {
++    OpenSSL_add_all_algorithms();
++    ERR_load_crypto_strings();
++}
++ 
++// 辅助函数,用于清理OpenSSL库
++void CleanupOpenSSL() {
++    EVP_cleanup();
++    ERR_free_strings();
++}
++ 
++// 测试类
++class RSACTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        InitOpenSSL();
++    }
++ 
++    void TearDown() override {
++        CleanupOpenSSL();
++    }
++ 
++    RSAC rsac;
++};
++ 
++// 测试密钥生成并保存到文件
++TEST_F(RSACTest, GenerateKeyPairToFile) {
++    QString priKeyFile = "test_private.pem";
++    QString pubKeyFile = "test_public.pem";
++    rsac.generateKeyPair(priKeyFile, pubKeyFile, 1024);
++ 
++    // 这里可以添加额外的检查来验证文件是否成功生成且内容有效
++    // 例如,打开文件并读取内容,检查是否为有效的PEM格式密钥
++    // 但由于这是一个简单的测试示例,我们省略了这些步骤
++}
++ 
++// 测试密钥生成并保存到QByteArray
++TEST_F(RSACTest, GenerateKeyPairToByteArray) {
++    QByteArray privateKey;
++    QByteArray publicKey;
++    rsac.generateKeyPair(privateKey, publicKey, 1024);
++ 
++    // 检查生成的密钥是否非空
++    EXPECT_FALSE(privateKey.isEmpty());
++    EXPECT_FALSE(publicKey.isEmpty());
++ 
++    // 这里可以添加额外的检查来验证密钥的有效性
++    // 例如,使用OpenSSL函数解析生成的密钥并检查其属性
++    // 但由于这是一个简单的测试示例,我们省略了这些步骤
++}
++ 
++// 测试加密和解密
++TEST_F(RSACTest, EncryptDecrypt) {
++    QByteArray privateKey;
++    QByteArray publicKey;
++    rsac.generateKeyPair(privateKey, publicKey, 1024);
++ 
++    QByteArray plaintext = "Hello, RSA!";
++    QByteArray ciphertext;
++    QByteArray decryptedtext;
++ 
++    bool encryptResult = rsac.encrypt(plaintext, ciphertext, publicKey);
++    EXPECT_TRUE(encryptResult);
++ 
++    bool decryptResult = rsac.decrypt(ciphertext, decryptedtext, privateKey);
++    EXPECT_TRUE(decryptResult);
++ 
++    EXPECT_EQ(plaintext, decryptedtext);
++}
++ 
++// 测试签名和验签
++TEST_F(RSACTest, SignVerify) {
++    QByteArray privateKey;
++    QByteArray publicKey;
++    rsac.generateKeyPair(privateKey, publicKey, 1024);
++ 
++    QByteArray message = "This is a test message.";
++    QByteArray signature;
++    bool signResult = rsac.sign(message, signature, privateKey);
++    EXPECT_TRUE(signResult);
++ 
++    bool verifyResult = rsac.verify(message, signature, publicKey);
++    EXPECT_TRUE(verifyResult);
++ 
++    // 尝试使用错误的消息进行验签,应该失败
++    bool verifyWithWrongMessageResult = rsac.verify("Wrong message.", signature, publicKey);
++    EXPECT_FALSE(verifyWithWrongMessageResult);
++}
++ 
++int main(int argc, char **argv) {
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_servicemanager/CMakeLists.txt b/tests/unit_test_servicemanager/CMakeLists.txt
+new file mode 100644
+index 0000000..efb3e92
+--- /dev/null
++++ b/tests/unit_test_servicemanager/CMakeLists.txt
+@@ -0,0 +1,58 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../uniauth-backend/src/servicemanager.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../uniauth-backend/src/servicemanager.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_servicemanager ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_servicemanager
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_servicemanager
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_servicemanager/main.cpp b/tests/unit_test_servicemanager/main.cpp
+new file mode 100644
+index 0000000..a0f7386
+--- /dev/null
++++ b/tests/unit_test_servicemanager/main.cpp
+@@ -0,0 +1,35 @@
++#include <gtest/gtest.h>
++#include "../../uniauth-backend/src/servicemanager.h"
++#include <QByteArray>
++#include <QDataStream>
++
++#define SERVICE "biometric-authentication.service"
++#define DBUS_SERVICE "org.ukui.Biometric"
++#define DBUS_PATH "/org/ukui/Biometric"
++#define DBUS_INTERFACE "org.ukui.Biometric"
++
++#define FD_DBUS_SERVICE     "org.freedesktop.DBus"
++#define FD_DBUS_PATH        "/org/freedesktop/DBus"
++#define FD_DBUS_INTERFACE   "org.freedesktop.DBus"
++ 
++// gtest 测试用例
++TEST(ServiceManagerTest, SerializationAndDeserialization) {
++    ServiceManager *sm = ServiceManager::instance();
++
++    sm->connectToService();
++    
++    sm->serviceStatusChanged(true);
++    sm->serviceStatusChanged(false);
++
++    sm->dbusNameOwnerChanged(DBUS_SERVICE,DBUS_SERVICE,DBUS_SERVICE);
++
++    sm->onDBusNameOwnerChanged(DBUS_SERVICE,DBUS_SERVICE,DBUS_SERVICE);
++    
++    sm->serviceExists();
++ 
++}
++ 
++int main(int argc, char **argv) {
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_sessionmanager/CMakeLists.txt b/tests/unit_test_sessionmanager/CMakeLists.txt
+new file mode 100644
+index 0000000..766ebf5
+--- /dev/null
++++ b/tests/unit_test_sessionmanager/CMakeLists.txt
+@@ -0,0 +1,59 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/sessionmanager.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/sessionmanager.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_sessionmanager ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_sessionmanager
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_sessionmanager
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_sessionmanager/main.cpp b/tests/unit_test_sessionmanager/main.cpp
+new file mode 100644
+index 0000000..83819b4
+--- /dev/null
++++ b/tests/unit_test_sessionmanager/main.cpp
+@@ -0,0 +1,34 @@
++// sessionmanager_test.cpp
++
++#include <gtest/gtest.h>
++#include <QCoreApplication>
++#include <QDBusConnection>
++#include <QDBusMessage>
++#include <QDBusInterface>
++#include <QDBusReply>
++#include <QDBusObjectPath>
++#include "../../polkit-agent/src/sessionmanager.h"
++
++// Test fixture for SessionManager
++class SessionManagerTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        sessionManager = new SessionManager();
++    }
++
++    void TearDown() override {
++        delete sessionManager;
++    }
++
++    SessionManager* sessionManager;
++};
++
++TEST_F(SessionManagerTest, testSessionManagerTest) {
++    EXPECT_TRUE(sessionManager != nullptr);
++}
++
++int main(int argc, char **argv) {
++    QCoreApplication *app = new QCoreApplication(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_usdblockshortcut/CMakeLists.txt b/tests/unit_test_usdblockshortcut/CMakeLists.txt
+new file mode 100644
+index 0000000..91f704f
+--- /dev/null
++++ b/tests/unit_test_usdblockshortcut/CMakeLists.txt
+@@ -0,0 +1,59 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/usdblockshortcut.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/usdblockshortcut.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_usdblockshortcut ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_usdblockshortcut
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_usdblockshortcut
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_usdblockshortcut/main.cpp b/tests/unit_test_usdblockshortcut/main.cpp
+new file mode 100644
+index 0000000..2d6cdd4
+--- /dev/null
++++ b/tests/unit_test_usdblockshortcut/main.cpp
+@@ -0,0 +1,35 @@
++// usdblockshortcut_test.cpp
++
++#include <gtest/gtest.h>
++#include <QCoreApplication>
++#include <QDBusConnection>
++#include <QDBusMessage>
++#include <QDBusInterface>
++#include <QDBusReply>
++#include <QDBusObjectPath>
++#include "../../polkit-agent/src/usdblockshortcut.h"
++
++// Test fixture for SessionManager
++class USDBlockShortCutTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        usdblockShortCut = new USDBlockShortCut();
++    }
++
++    void TearDown() override {
++        delete usdblockShortCut;
++    }
++
++    USDBlockShortCut *usdblockShortCut;
++};
++
++TEST_F(USDBlockShortCutTest, testUSDBlockShortCutTest) {
++    EXPECT_TRUE(usdblockShortCut != nullptr);
++    usdblockShortCut->blockShortcuts(); 
++}
++
++int main(int argc, char **argv) {
++    QCoreApplication *app = new QCoreApplication(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/tests/unit_test_users/CMakeLists.txt b/tests/unit_test_users/CMakeLists.txt
+new file mode 100644
+index 0000000..a1efcbf
+--- /dev/null
++++ b/tests/unit_test_users/CMakeLists.txt
+@@ -0,0 +1,59 @@
++# CMake 最低版本要求
++cmake_minimum_required(VERSION 3.10)
++
++find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED)
++
++find_package(PkgConfig REQUIRED)
++
++# 包含 GTest 库和 pthread 库
++find_package(GTest REQUIRED)
++find_package(Threads REQUIRED)
++
++# 设置 C++ 标准
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++
++# 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置)
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control")
++set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
++
++# 定义源文件列表,对应原来的SOURCES变量
++set(SOURCES
++    ../../polkit-agent/src/users.cpp
++    main.cpp
++)
++
++# 定义头文件列表,对应原来的HEADERS变量
++set(HEADERS
++    ../../polkit-agent/src/users.h
++)
++
++# 包含头文件的路径设置,对应原来的INCLUDEPATH变量
++include_directories(
++    ${CMAKE_CURRENT_SOURCE_DIR}
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub
++    ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext
++)
++
++# 使用qt5_wrap_cpp生成元对象代码相关的源文件
++qt5_wrap_cpp(MOC_SOURCES ${HEADERS})
++
++# 添加可执行文件或库目标,将元对象代码源文件一起添加进去
++add_executable(unit_test_users ${SOURCES} ${MOC_SOURCES})
++
++# 链接Qt相关的库
++target_link_libraries(unit_test_users
++    Qt5::Core
++    Qt5::Gui
++    Qt5::DBus
++    Qt5::Widgets
++)
++
++# 链接 GTest 库
++target_link_libraries(unit_test_users
++    GTest::GTest
++    GTest::Main
++    Threads::Threads
++)
++
+diff --git a/tests/unit_test_users/main.cpp b/tests/unit_test_users/main.cpp
+new file mode 100644
+index 0000000..d51094b
+--- /dev/null
++++ b/tests/unit_test_users/main.cpp
+@@ -0,0 +1,86 @@
++#include <gtest/gtest.h>
++#include "../../polkit-agent/src/users.h"
++#include <QCoreApplication>
++#include <QDBusInterface>
++#include <QDBusMessage>
++#include <QDBusArgument>
++#include <QDebug>
++#include <QFile>
++#include <QTemporaryDir>
++
++class UsersTest : public ::testing::Test {
++protected:
++    void SetUp() override {
++        users = new Users(nullptr);
++    }
++
++    void TearDown() override {
++        delete users;
++    }
++
++    Users *users;
++};
++
++TEST_F(UsersTest, testGetUsers) {
++    QList<UserItem> userList = users->getUsers();
++    EXPECT_EQ(userList.size(), 0);  // Initially, the list should be empty
++
++    // Load users should populate the list
++    users->loadUsers();
++    userList = users->getUsers();
++    EXPECT_EQ(userList.size(), 2);  // After loading, we expect 2 users
++    EXPECT_EQ(userList[0].name, QString("testuser"));
++    EXPECT_EQ(userList[0].uid, quint64(1000));
++    EXPECT_EQ(userList[1].name, QString(""));  // The second user might not be fully populated in this mock
++}
++
++TEST_F(UsersTest, testGetUserByName) {
++    users->loadUsers();
++    UserItem user = users->getUserByName("testuser");
++    EXPECT_EQ(user.name, QString("testuser"));
++    EXPECT_EQ(user.realName, QString("Test User"));
++    EXPECT_EQ(user.uid, quint64(1000));
++
++    user = users->getUserByName("nonexistent");
++    EXPECT_EQ(user.name, QString("nonexistent"));
++    EXPECT_EQ(user.uid, ::getuid());  // Fallback uid should be the current uid
++
++    user = users->getUserByName("root");
++    user = users->getUserByName("kylin");
++    qDebug()<<user;
++}
++
++TEST_F(UsersTest, testGetDefaultIcon) {
++    QString defaultIcon = users->getDefaultIcon();
++    EXPECT_EQ(defaultIcon, QString(":/image/assets/iconFace.png"));
++}
++
++TEST_F(UsersTest, testOnUserAddedAndDeleted) {
++    // Set up a temporary directory and file to test icon loading
++    QTemporaryDir tempDir;
++    QFile tempFile(tempDir.filePath("icon.png"));
++    tempFile.open(QIODevice::WriteOnly);
++    tempFile.close();
++
++    // Load users
++    users->loadUsers();
++    QList<UserItem> userList = users->getUsers();
++    EXPECT_EQ(userList.size(), 2);
++
++    // Emit userAdded signal (simulate DBus signal)
++    QDBusObjectPath path("/user/newuser");
++    QMetaObject::invokeMethod(users, "onUserAdded", Q_ARG(QDBusObjectPath, path));
++    userList = users->getUsers();
++    EXPECT_EQ(userList.size(), 3);  // Now we should have 3 users
++
++    // Emit userDeleted signal (simulate DBus signal)
++    QMetaObject::invokeMethod(users, "onUserDeleted", Q_ARG(QDBusObjectPath, path));
++    userList = users->getUsers();
++    EXPECT_EQ(userList.size(), 2);  // Back to 2 users
++}
++
++int main(int argc, char **argv) {
++    QCoreApplication *app = new QCoreApplication(argc, argv);
++    ::testing::InitGoogleTest(&argc, argv);
++    return RUN_ALL_TESTS();
++}
+diff --git a/uniauth-backend/src/main.cpp b/uniauth-backend/src/main.cpp
+index b472046..0fcc677 100644
+--- a/uniauth-backend/src/main.cpp
++++ b/uniauth-backend/src/main.cpp
+@@ -19,16 +19,18 @@
+ #include "serviceinterface.h"
+ #include "personalizeddata.h"
+ #include <ukui-log4qt.h>
++#include <syslog.h>
+ 
+ int main(int argc, char *argv[])
+ {
++    syslog(LOG_INFO, "[uniauth-backend] start begin!");
+     initUkuiLog4qt("ukui-biometric-uniauth");
+     QCoreApplication a(argc, argv);
+-
++    syslog(LOG_INFO, "[uniauth-backend] KYLINUSERDATAMNG initing!");
+     KYLINUSERDATAMNG::instance();
+-
++    syslog(LOG_INFO, "[uniauth-backend] KYLINUSERDATAMNG inited!");
+     ServiceInterface serviveInterface;
+     Q_UNUSED(serviveInterface);
+-
++    syslog(LOG_INFO, "[uniauth-backend] qcoreapplication eventloop begin!");
+     return a.exec();
+ }
+diff --git a/uniauth-backend/src/personalizeddata.cpp b/uniauth-backend/src/personalizeddata.cpp
+index a5a0a97..4796d88 100644
+--- a/uniauth-backend/src/personalizeddata.cpp
++++ b/uniauth-backend/src/personalizeddata.cpp
+@@ -240,10 +240,18 @@ QString PersonalizedData::__copy_file(QString oldfile)
+ 
+ PersonalizedDataMng::PersonalizedDataMng(void)
+ {
++}
++
++void PersonalizedDataMng::initData()
++{
++    if (m_isDataInited) {
++        return;
++    }
+     m_usersModel = new QLightDM::UsersModel(this);
+     connect(m_usersModel, &QAbstractListModel::rowsInserted, this, &PersonalizedDataMng::onUserAdded);
+     connect(m_usersModel, &QAbstractListModel::rowsRemoved, this, &PersonalizedDataMng::onUserRemoved);
+     this->__updateUsersInfo();
++    m_isDataInited = true;
+ }
+ 
+ PersonalizedDataMng::~PersonalizedDataMng()
+@@ -257,6 +265,7 @@ PersonalizedDataMng::~PersonalizedDataMng()
+ 
+ QString PersonalizedDataMng::GetConfInformation(QString name)
+ {
++    initData();
+     QJsonObject json;
+     if(m_userPersonalizedData.contains(name))
+     {
+diff --git a/uniauth-backend/src/personalizeddata.h b/uniauth-backend/src/personalizeddata.h
+index 1c6dafc..b71c259 100644
+--- a/uniauth-backend/src/personalizeddata.h
++++ b/uniauth-backend/src/personalizeddata.h
+@@ -145,11 +145,17 @@ protected Q_SLOTS:
+ protected:
+     void __updateUsersInfo();
+ 
++private:
++    void initData();
++
+ protected:
+     QMap<QString, KylinUserDatePtr > m_userPersonalizedData;
+     QLightDM::UsersModel  * m_usersModel = nullptr;
+     QString m_lightdm_str;
+     friend class SingleTon<PersonalizedDataMng>;
++
++private:
++    bool m_isDataInited = false;
+ };
+ 
+ typedef SingleTon<PersonalizedDataMng>  KYLINUSERDATAMNG;
+diff --git a/uniauth-backend/src/serviceinterface.cpp b/uniauth-backend/src/serviceinterface.cpp
+index 1399dae..ed1012a 100644
+--- a/uniauth-backend/src/serviceinterface.cpp
++++ b/uniauth-backend/src/serviceinterface.cpp
+@@ -14,7 +14,7 @@
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, see <http://www.gnu.org/licenses/>.
+  *
+-**/
++ **/
+ #include "serviceinterface.h"
+ #include <QDBusConnection>
+ #include <QSettings>
+@@ -39,85 +39,112 @@
+ #include <unistd.h>
+ #include <openssl/rsa.h>
+ #include <openssl/pem.h>
++#include <syslog.h>
+ 
+-#define UKUI_GREETER        "/usr/sbin/ukui-greeter"
+-#define UKUI_SCREENSAVER    "/usr/bin/ukui-screensaver-backend"
++#define UKUI_GREETER "/usr/sbin/ukui-greeter"
++#define UKUI_SCREENSAVER "/usr/bin/ukui-screensaver-backend"
+ 
+-#define GREETER_DBUS_PATH           "/"
+-#define GREETER_DBUS_INTERFACE      "org.ukui.greeter"
+-#define SCREENSAVER_DBUS_PATH       "/"
+-#define SCREENSAVER_DBUS_INTERFACE  "org.ukui.screensaver"
++#define GREETER_DBUS_PATH "/"
++#define GREETER_DBUS_INTERFACE "org.ukui.greeter"
++#define SCREENSAVER_DBUS_PATH "/"
++#define SCREENSAVER_DBUS_INTERFACE "org.ukui.screensaver"
+ #define COMM_CONFIG_PATH "/etc/biometric-auth/ukui-biometric.conf"
+ #define USER_CONFIG_PATH "/home/%1/.biometric_auth/ukui_biometric.conf"
+ #define OLD_990_USER_CONFIG_PATH "/home/%1/.biometric-auth/ukui-biometric.conf"
+ #define PROC_CPUINFO "/proc/cpuinfo"
++#define LAST_LOGIN_INFO_PATH "/var/lib/lightdm/.cache/ukui-greeter.conf"
++
++/* For the type WillLoginUserInfo */
++QDBusArgument &operator<<(QDBusArgument &argument, const WillLoginUserInfo &willLoginUserInfo)
++{
++    argument.beginStructure();
++    argument << willLoginUserInfo.strUserName << willLoginUserInfo.isOneKeyLogin;
++    argument.endStructure();
++    return argument;
++}
++
++const QDBusArgument &operator>>(const QDBusArgument &argument, WillLoginUserInfo &willLoginUserInfo)
++{
++    argument.beginStructure();
++    argument >> willLoginUserInfo.strUserName >> willLoginUserInfo.isOneKeyLogin;
++    argument.endStructure();
++    return argument;
++}
++
++QDebug operator<<(QDebug stream, const WillLoginUserInfo &willLoginUserInfo)
++{
++    stream << "WillLogUser [" << willLoginUserInfo.strUserName << willLoginUserInfo.isOneKeyLogin << "]";
++    return stream;
++}
+ 
+ ServiceInterface::ServiceInterface()
+ {
++    syslog(LOG_INFO, "[uniauth-backend] ServiceInterface init begin");
+     bool res = QDBusConnection::systemBus().registerService("org.ukui.UniauthBackend");
+-    if(!res){
+-        qInfo()<<"registerService org.ukui.UniauthBackend failed!!";
++    if (!res) {
++        qInfo() << "registerService org.ukui.UniauthBackend failed!!";
+         exit(0);
+     }
+-    res = QDBusConnection::systemBus().registerObject("/org/ukui/UniauthBackend", "org.ukui.UniauthBackend",
+-                                                      this, QDBusConnection::ExportAllSlots|QDBusConnection::ExportAllSignals);
+-    if(!res){
+-        qInfo()<<"registerObject /org/ukui/UniauthBackend failed!!";
++    res = QDBusConnection::systemBus().registerObject(
++        "/org/ukui/UniauthBackend",
++        "org.ukui.UniauthBackend",
++        this,
++        QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals);
++    if (!res) {
++        qInfo() << "registerObject /org/ukui/UniauthBackend failed!!";
+         exit(0);
+     }
+-
+     registerCustomTypes();
++    qRegisterMetaType<WillLoginUserInfo>("WillLoginUserInfo");
++    qDBusRegisterMetaType<WillLoginUserInfo>();
+     checkIs990();
+-    m_serviceInterface = new QDBusInterface(DBUS_SERVICE, DBUS_PATH,
+-                                            DBUS_INTERFACE,
+-                                            QDBusConnection::systemBus(), this);
++    m_serviceInterface
++        = new QDBusInterface(DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE, QDBusConnection::systemBus(), this);
+ 
+     m_serviceInterface->setTimeout(2147483647);
+-    connect(m_serviceInterface, SIGNAL(USBDeviceHotPlug(int, int, int)),
+-            this, SLOT(onUSBDeviceHotPlug(int,int,int)));
+-    updateCommDefaultDevice(-1);
+-    initData();
+-
++    connect(m_serviceInterface, SIGNAL(USBDeviceHotPlug(int, int, int)), this, SLOT(onUSBDeviceHotPlug(int, int, int)));
+     ServiceManager *sm = ServiceManager::instance();
+-    connect(sm, &ServiceManager::serviceStatusChanged,
+-            this, &ServiceInterface::onBiometricDbusChanged);
+-
+-    rsac.generateKeyPair(priKey, pubKey, 1024);
+-    connect(KYLINUSERDATAMNG::getInstance(), &PersonalizedDataMng::conf_changed, this, &ServiceInterface::updateUserInformation);
++    connect(sm, &ServiceManager::serviceStatusChanged, this, &ServiceInterface::onBiometricDbusChanged);
++    connect(
++        KYLINUSERDATAMNG::getInstance(),
++        &PersonalizedDataMng::conf_changed,
++        this,
++        &ServiceInterface::updateUserInformation);
++    syslog(LOG_INFO, "[uniauth-backend] ServiceInterface init end");
+ }
+ 
+ void ServiceInterface::setDefaultDevice(QString userName, int bioDevType, QString deviceName)
+ {
+     QString configPath = QString(USER_CONFIG_PATH).arg(userName);
+-    qDebug() << configPath << bioDevType ;
++    qDebug() << configPath << bioDevType;
+     QSettings settings(configPath, QSettings::IniFormat);
+     switch (bioDevType) {
+-    case BIOTYPE_FACE:
+-        settings.setValue("FC_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_FINGERPRINT:
+-        settings.setValue("FP_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_FINGERVEIN:
+-        settings.setValue("FV_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_IRIS:
+-        settings.setValue("IR_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_VOICEPRINT:
+-        settings.setValue("VP_DefaultDevice", deviceName);
+-        break;
+-    case UNIT_GENERAL_UKEY:
+-        settings.setValue("GU_DefaultDevice",deviceName);
+-        break;
+-    case REMOTE_QRCODE_TYPE:
+-        settings.setValue("WC_DefaultDevice", deviceName);
+-        break;
+-    default:
+-        break;
++        case BIOTYPE_FACE:
++            settings.setValue("FC_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_FINGERPRINT:
++            settings.setValue("FP_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_FINGERVEIN:
++            settings.setValue("FV_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_IRIS:
++            settings.setValue("IR_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_VOICEPRINT:
++            settings.setValue("VP_DefaultDevice", deviceName);
++            break;
++        case UNIT_GENERAL_UKEY:
++            settings.setValue("GU_DefaultDevice", deviceName);
++            break;
++        case REMOTE_QRCODE_TYPE:
++            settings.setValue("WC_DefaultDevice", deviceName);
++            break;
++        default:
++            break;
+     }
+     settings.sync();
+-    qDebug()<<"setDefaultDevice:"<<userName<<","<<bioDevType<<","<<deviceName;
++    qDebug() << "setDefaultDevice:" << userName << "," << bioDevType << "," << deviceName;
+     emit defaultDeviceChanged(userName, bioDevType, deviceName);
+ }
+ 
+@@ -130,12 +157,13 @@ void ServiceInterface::setDefaultDevice(int bioDevType, QString deviceName)
+     if (pwinfo && pwinfo->pw_name) {
+         setDefaultDevice(pwinfo->pw_name, bioDevType, deviceName);
+     } else {
+-        qInfo()<<"GetPWInfo failed!!";
++        qInfo() << "GetPWInfo failed!!";
+     }
+ }
+ 
+ QString ServiceInterface::getDefaultDevice(QString userName, int bioDevType)
+ {
++    initData();
+     QString defaultDevice = "";
+     QString configPath = QString(USER_CONFIG_PATH).arg(userName);
+     QSettings settings(configPath, QSettings::IniFormat);
+@@ -146,30 +174,30 @@ QString ServiceInterface::getDefaultDevice(QString userName, int bioDevType)
+             for (auto devInfo : m_listDeviceInfos) {
+                 if (devInfo && devInfo->device_shortname == strOldDefDev) {
+                     QString strBioDefType = "";
+-                    switch(devInfo->biotype) {
+-                    case BIOTYPE_FINGERPRINT:
+-                        strBioDefType = "FP_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FINGERVEIN:
+-                        strBioDefType = "FV_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_IRIS:
+-                        strBioDefType = "IR_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FACE:
+-                        strBioDefType = "FC_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_VOICEPRINT:
+-                        strBioDefType = "VP_DefaultDevice";
+-                        break;
+-                    case UNIT_GENERAL_UKEY:
+-                        strBioDefType = "GU_DefaultDevice";
+-                        break;
+-                    case REMOTE_QRCODE_TYPE:
+-                        strBioDefType = "WC_DefaultDevice";
+-                        break;
+-                    default:
+-                        break;
++                    switch (devInfo->biotype) {
++                        case BIOTYPE_FINGERPRINT:
++                            strBioDefType = "FP_DefaultDevice";
++                            break;
++                        case BIOTYPE_FINGERVEIN:
++                            strBioDefType = "FV_DefaultDevice";
++                            break;
++                        case BIOTYPE_IRIS:
++                            strBioDefType = "IR_DefaultDevice";
++                            break;
++                        case BIOTYPE_FACE:
++                            strBioDefType = "FC_DefaultDevice";
++                            break;
++                        case BIOTYPE_VOICEPRINT:
++                            strBioDefType = "VP_DefaultDevice";
++                            break;
++                        case UNIT_GENERAL_UKEY:
++                            strBioDefType = "GU_DefaultDevice";
++                            break;
++                        case REMOTE_QRCODE_TYPE:
++                            strBioDefType = "WC_DefaultDevice";
++                            break;
++                        default:
++                            break;
+                     }
+                     if (!strBioDefType.isEmpty() && !settings.contains(strBioDefType)) {
+                         settings.setValue(strBioDefType, strOldDefDev);
+@@ -185,58 +213,58 @@ QString ServiceInterface::getDefaultDevice(QString userName, int bioDevType)
+         }
+     }
+     switch (bioDevType) {
+-    case BIOTYPE_FACE:
+-        defaultDevice = settings.value("FC_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_FINGERPRINT:
+-        defaultDevice = settings.value("FP_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_FINGERVEIN:
+-        defaultDevice = settings.value("FV_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_IRIS:
+-        defaultDevice = settings.value("IR_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_VOICEPRINT:
+-        defaultDevice = settings.value("VP_DefaultDevice").toString();
+-        break;
+-    case UNIT_GENERAL_UKEY:
+-        defaultDevice = settings.value("GU_DefaultDevice").toString();
+-        break;
+-    case REMOTE_QRCODE_TYPE:
+-        defaultDevice = settings.value("WC_DefaultDevice").toString();
+-        break;
+-    default:
+-        defaultDevice = settings.value("DefaultDevice").toString();
+-        break;
+-    }
+-    if(defaultDevice.isEmpty()) {
+-        QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat);
+-        switch (bioDevType) {
+         case BIOTYPE_FACE:
+-            defaultDevice = settings2.value("FC_DefaultDevice").toString();
++            defaultDevice = settings.value("FC_DefaultDevice").toString();
+             break;
+         case BIOTYPE_FINGERPRINT:
+-            defaultDevice = settings2.value("FP_DefaultDevice").toString();
++            defaultDevice = settings.value("FP_DefaultDevice").toString();
+             break;
+         case BIOTYPE_FINGERVEIN:
+-            defaultDevice = settings2.value("FV_DefaultDevice").toString();
++            defaultDevice = settings.value("FV_DefaultDevice").toString();
+             break;
+         case BIOTYPE_IRIS:
+-            defaultDevice = settings2.value("IR_DefaultDevice").toString();
++            defaultDevice = settings.value("IR_DefaultDevice").toString();
+             break;
+         case BIOTYPE_VOICEPRINT:
+-            defaultDevice = settings2.value("VP_DefaultDevice").toString();
++            defaultDevice = settings.value("VP_DefaultDevice").toString();
+             break;
+         case UNIT_GENERAL_UKEY:
+-            defaultDevice = settings2.value("GU_DefaultDevice").toString();
++            defaultDevice = settings.value("GU_DefaultDevice").toString();
+             break;
+         case REMOTE_QRCODE_TYPE:
+-            defaultDevice = settings2.value("WC_DefaultDevice").toString();
++            defaultDevice = settings.value("WC_DefaultDevice").toString();
+             break;
+         default:
+-            defaultDevice = settings2.value("DefaultDevice").toString();
++            defaultDevice = settings.value("DefaultDevice").toString();
+             break;
++    }
++    if (defaultDevice.isEmpty()) {
++        QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat);
++        switch (bioDevType) {
++            case BIOTYPE_FACE:
++                defaultDevice = settings2.value("FC_DefaultDevice").toString();
++                break;
++            case BIOTYPE_FINGERPRINT:
++                defaultDevice = settings2.value("FP_DefaultDevice").toString();
++                break;
++            case BIOTYPE_FINGERVEIN:
++                defaultDevice = settings2.value("FV_DefaultDevice").toString();
++                break;
++            case BIOTYPE_IRIS:
++                defaultDevice = settings2.value("IR_DefaultDevice").toString();
++                break;
++            case BIOTYPE_VOICEPRINT:
++                defaultDevice = settings2.value("VP_DefaultDevice").toString();
++                break;
++            case UNIT_GENERAL_UKEY:
++                defaultDevice = settings2.value("GU_DefaultDevice").toString();
++                break;
++            case REMOTE_QRCODE_TYPE:
++                defaultDevice = settings2.value("WC_DefaultDevice").toString();
++                break;
++            default:
++                defaultDevice = settings2.value("DefaultDevice").toString();
++                break;
+         }
+     }
+     return defaultDevice;
+@@ -244,6 +272,7 @@ QString ServiceInterface::getDefaultDevice(QString userName, int bioDevType)
+ 
+ QStringList ServiceInterface::getAllDefaultDevice(QString userName)
+ {
++    initData();
+     QStringList listDefDevice;
+     QString configPath = QString(USER_CONFIG_PATH).arg(userName);
+     QSettings settings(configPath, QSettings::IniFormat);
+@@ -255,30 +284,30 @@ QStringList ServiceInterface::getAllDefaultDevice(QString userName)
+             for (auto devInfo : m_listDeviceInfos) {
+                 if (devInfo && devInfo->device_shortname == strOldDefDev) {
+                     QString strBioDefType = "";
+-                    switch(devInfo->biotype) {
+-                    case BIOTYPE_FINGERPRINT:
+-                        strBioDefType = "FP_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FINGERVEIN:
+-                        strBioDefType = "FV_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_IRIS:
+-                        strBioDefType = "IR_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FACE:
+-                        strBioDefType = "FC_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_VOICEPRINT:
+-                        strBioDefType = "VP_DefaultDevice";
+-                        break;
+-                    case UNIT_GENERAL_UKEY:
+-                        strBioDefType = "GU_DefaultDevice";
+-                        break;
+-                    case REMOTE_QRCODE_TYPE:
+-                        strBioDefType = "WC_DefaultDevice";
+-                        break;
+-                    default:
+-                        break;
++                    switch (devInfo->biotype) {
++                        case BIOTYPE_FINGERPRINT:
++                            strBioDefType = "FP_DefaultDevice";
++                            break;
++                        case BIOTYPE_FINGERVEIN:
++                            strBioDefType = "FV_DefaultDevice";
++                            break;
++                        case BIOTYPE_IRIS:
++                            strBioDefType = "IR_DefaultDevice";
++                            break;
++                        case BIOTYPE_FACE:
++                            strBioDefType = "FC_DefaultDevice";
++                            break;
++                        case BIOTYPE_VOICEPRINT:
++                            strBioDefType = "VP_DefaultDevice";
++                            break;
++                        case UNIT_GENERAL_UKEY:
++                            strBioDefType = "GU_DefaultDevice";
++                            break;
++                        case REMOTE_QRCODE_TYPE:
++                            strBioDefType = "WC_DefaultDevice";
++                            break;
++                        default:
++                            break;
+                     }
+                     if (!strBioDefType.isEmpty() && !settings.contains(strBioDefType)) {
+                         nOldDefType = devInfo->biotype;
+@@ -298,55 +327,55 @@ QStringList ServiceInterface::getAllDefaultDevice(QString userName)
+         if (nBioType == nOldDefType)
+             continue;
+         switch (nBioType) {
+-        case BIOTYPE_FACE:
+-            defaultDevice = settings.value("FC_DefaultDevice").toString();
+-            break;
+-        case BIOTYPE_FINGERPRINT:
+-            defaultDevice = settings.value("FP_DefaultDevice").toString();
+-            break;
+-        case BIOTYPE_FINGERVEIN:
+-            defaultDevice = settings.value("FV_DefaultDevice").toString();
+-            break;
+-        case BIOTYPE_IRIS:
+-            defaultDevice = settings.value("IR_DefaultDevice").toString();
+-            break;
+-        case BIOTYPE_VOICEPRINT:
+-            defaultDevice = settings.value("VP_DefaultDevice").toString();
+-            break;
+-        case UNIT_GENERAL_UKEY:
+-            defaultDevice = settings.value("GU_DefaultDevice").toString();
+-            break;
+-        case REMOTE_QRCODE_TYPE:
+-            defaultDevice = settings.value("WC_DefaultDevice").toString();
+-            break;
+-        default:
+-            break;
+-        }
+-        if(defaultDevice.isEmpty()) {
+-            switch (nBioType) {
+             case BIOTYPE_FACE:
+-                defaultDevice = settings2.value("FC_DefaultDevice").toString();
++                defaultDevice = settings.value("FC_DefaultDevice").toString();
+                 break;
+             case BIOTYPE_FINGERPRINT:
+-                defaultDevice = settings2.value("FP_DefaultDevice").toString();
++                defaultDevice = settings.value("FP_DefaultDevice").toString();
+                 break;
+             case BIOTYPE_FINGERVEIN:
+-                defaultDevice = settings2.value("FV_DefaultDevice").toString();
++                defaultDevice = settings.value("FV_DefaultDevice").toString();
+                 break;
+             case BIOTYPE_IRIS:
+-                defaultDevice = settings2.value("IR_DefaultDevice").toString();
++                defaultDevice = settings.value("IR_DefaultDevice").toString();
+                 break;
+             case BIOTYPE_VOICEPRINT:
+-                defaultDevice = settings2.value("VP_DefaultDevice").toString();
++                defaultDevice = settings.value("VP_DefaultDevice").toString();
+                 break;
+             case UNIT_GENERAL_UKEY:
+-                defaultDevice = settings2.value("GU_DefaultDevice").toString();
++                defaultDevice = settings.value("GU_DefaultDevice").toString();
+                 break;
+             case REMOTE_QRCODE_TYPE:
+-                defaultDevice = settings2.value("WC_DefaultDevice").toString();
++                defaultDevice = settings.value("WC_DefaultDevice").toString();
+                 break;
+             default:
+                 break;
++        }
++        if (defaultDevice.isEmpty()) {
++            switch (nBioType) {
++                case BIOTYPE_FACE:
++                    defaultDevice = settings2.value("FC_DefaultDevice").toString();
++                    break;
++                case BIOTYPE_FINGERPRINT:
++                    defaultDevice = settings2.value("FP_DefaultDevice").toString();
++                    break;
++                case BIOTYPE_FINGERVEIN:
++                    defaultDevice = settings2.value("FV_DefaultDevice").toString();
++                    break;
++                case BIOTYPE_IRIS:
++                    defaultDevice = settings2.value("IR_DefaultDevice").toString();
++                    break;
++                case BIOTYPE_VOICEPRINT:
++                    defaultDevice = settings2.value("VP_DefaultDevice").toString();
++                    break;
++                case UNIT_GENERAL_UKEY:
++                    defaultDevice = settings2.value("GU_DefaultDevice").toString();
++                    break;
++                case REMOTE_QRCODE_TYPE:
++                    defaultDevice = settings2.value("WC_DefaultDevice").toString();
++                    break;
++                default:
++                    break;
+             }
+         }
+         if (!defaultDevice.isEmpty()) {
+@@ -356,70 +385,72 @@ QStringList ServiceInterface::getAllDefaultDevice(QString userName)
+     return listDefDevice;
+ }
+ 
+-//设置通用默认设备
++// 设置通用默认设备
+ void ServiceInterface::setCommDefaultDevice(int bioDevType, QString deviceName)
+ {
++    initData();
+     QSettings settings(COMM_CONFIG_PATH, QSettings::IniFormat);
+     switch (bioDevType) {
+-    case BIOTYPE_FACE:
+-        settings.setValue("FC_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_FINGERPRINT:
+-        settings.setValue("FP_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_FINGERVEIN:
+-        settings.setValue("FV_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_IRIS:
+-        settings.setValue("IR_DefaultDevice", deviceName);
+-        break;
+-    case BIOTYPE_VOICEPRINT:
+-        settings.setValue("VP_DefaultDevice", deviceName);
+-        break;
+-    case UNIT_GENERAL_UKEY:
+-        settings.setValue("GU_DefaultDevice", deviceName);
+-        break;
+-    case REMOTE_QRCODE_TYPE:
+-        settings.setValue("WC_DefaultDevice", deviceName);
+-        break;
+-    default:
+-        break;
++        case BIOTYPE_FACE:
++            settings.setValue("FC_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_FINGERPRINT:
++            settings.setValue("FP_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_FINGERVEIN:
++            settings.setValue("FV_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_IRIS:
++            settings.setValue("IR_DefaultDevice", deviceName);
++            break;
++        case BIOTYPE_VOICEPRINT:
++            settings.setValue("VP_DefaultDevice", deviceName);
++            break;
++        case UNIT_GENERAL_UKEY:
++            settings.setValue("GU_DefaultDevice", deviceName);
++            break;
++        case REMOTE_QRCODE_TYPE:
++            settings.setValue("WC_DefaultDevice", deviceName);
++            break;
++        default:
++            break;
+     }
+     settings.sync();
+-    qDebug()<<"setCommDefaultDevice:"<<bioDevType<<","<<deviceName;
++    qDebug() << "setCommDefaultDevice:" << bioDevType << "," << deviceName;
+     emit defaultDeviceChanged("", bioDevType, deviceName);
+ }
+ 
+-//获取通用默认设备
++// 获取通用默认设备
+ QString ServiceInterface::getCommDefaultDevice(int bioDevType)
+ {
++    initData();
+     QString defaultDevice = "";
+     QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat);
+     switch (bioDevType) {
+-    case BIOTYPE_FACE:
+-        defaultDevice = settings2.value("FC_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_FINGERPRINT:
+-        defaultDevice = settings2.value("FP_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_FINGERVEIN:
+-        defaultDevice = settings2.value("FV_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_IRIS:
+-        defaultDevice = settings2.value("IR_DefaultDevice").toString();
+-        break;
+-    case BIOTYPE_VOICEPRINT:
+-        defaultDevice = settings2.value("VP_DefaultDevice").toString();
+-        break;
+-    case UNIT_GENERAL_UKEY:
+-        defaultDevice = settings2.value("GU_DefaultDevice").toString();
+-        break;
+-    case REMOTE_QRCODE_TYPE:
+-        defaultDevice = settings2.value("WC_DefaultDevice").toString();
+-        break;
+-    default:
+-        defaultDevice = settings2.value("DefaultDevice").toString();
+-        break;
++        case BIOTYPE_FACE:
++            defaultDevice = settings2.value("FC_DefaultDevice").toString();
++            break;
++        case BIOTYPE_FINGERPRINT:
++            defaultDevice = settings2.value("FP_DefaultDevice").toString();
++            break;
++        case BIOTYPE_FINGERVEIN:
++            defaultDevice = settings2.value("FV_DefaultDevice").toString();
++            break;
++        case BIOTYPE_IRIS:
++            defaultDevice = settings2.value("IR_DefaultDevice").toString();
++            break;
++        case BIOTYPE_VOICEPRINT:
++            defaultDevice = settings2.value("VP_DefaultDevice").toString();
++            break;
++        case UNIT_GENERAL_UKEY:
++            defaultDevice = settings2.value("GU_DefaultDevice").toString();
++            break;
++        case REMOTE_QRCODE_TYPE:
++            defaultDevice = settings2.value("WC_DefaultDevice").toString();
++            break;
++        default:
++            defaultDevice = settings2.value("DefaultDevice").toString();
++            break;
+     }
+     return defaultDevice;
+ }
+@@ -434,83 +465,84 @@ void ServiceInterface::setBioAuthStatus(int bioAuthType, bool status)
+         QString configPath = QString(USER_CONFIG_PATH).arg(pwinfo->pw_name);
+         QSettings settings(configPath, QSettings::IniFormat);
+         switch (bioAuthType) {
++            case ENABLETYPE_BIO:
++                settings.setValue("EnableAuth", status);
++                break;
++            case ENABLETYPE_SAVER:
++                settings.setValue("SaverEnable", status);
++                break;
++            case ENABLETYPE_GREETER:
++                settings.setValue("GreeterEnable", status);
++                break;
++            case ENABLETYPE_POLKIT:
++                settings.setValue("PolkitEnable", status);
++                break;
++            case ENABLETYPE_SU:
++                settings.setValue("SuEnable", status);
++                break;
++            case ENABLETYPE_SUDO:
++                settings.setValue("SudoEnable", status);
++                break;
++            case ENABLETYPE_LOGIN:
++                settings.setValue("LoginEnable", status);
++                break;
++            default:
++                break;
++        }
++        settings.sync();
++        emit bioAuthStatusChanged(pwinfo->pw_name, bioAuthType, status);
++        qDebug() << "setBioAuthStatus:" << pwinfo->pw_name << "," << bioAuthType << "," << status;
++    } else {
++        qInfo() << "GetPWInfo failed!!";
++    }
++}
++
++bool ServiceInterface::getBioAuthStatus(QString userName, int bioAuthType)
++{
++    initData();
++    QString configPath = QString(USER_CONFIG_PATH).arg(userName);
++    QSettings settings(configPath, QSettings::IniFormat);
++    QString strBioAuthType = "";
++    switch (bioAuthType) {
+         case ENABLETYPE_BIO:
+-            settings.setValue("EnableAuth", status);
++            strBioAuthType = "EnableAuth";
+             break;
+         case ENABLETYPE_SAVER:
+-            settings.setValue("SaverEnable", status);
++            strBioAuthType = "SaverEnable";
+             break;
+         case ENABLETYPE_GREETER:
+-            settings.setValue("GreeterEnable", status);
++            strBioAuthType = "GreeterEnable";
+             break;
+         case ENABLETYPE_POLKIT:
+-            settings.setValue("PolkitEnable", status);
++            strBioAuthType = "PolkitEnable";
+             break;
+         case ENABLETYPE_SU:
+-            settings.setValue("SuEnable", status);
++            strBioAuthType = "SuEnable";
+             break;
+         case ENABLETYPE_SUDO:
+-            settings.setValue("SudoEnable", status);
++            strBioAuthType = "SudoEnable";
+             break;
+         case ENABLETYPE_LOGIN:
+-            settings.setValue("LoginEnable", status);
++            strBioAuthType = "LoginEnable";
+             break;
+         default:
+-            break;
+-        }
+-        settings.sync();
+-        emit bioAuthStatusChanged(pwinfo->pw_name, bioAuthType, status);
+-        qDebug()<<"setBioAuthStatus:"<<pwinfo->pw_name<<","<<bioAuthType<<","<<status;
+-    } else {
+-        qInfo()<<"GetPWInfo failed!!";
+-    }
+-}
+-
+-bool ServiceInterface::getBioAuthStatus(QString userName, int bioAuthType)
+-{
+-    QString configPath = QString(USER_CONFIG_PATH).arg(userName);
+-    QSettings settings(configPath, QSettings::IniFormat);
+-    QString strBioAuthType = "";
+-    switch (bioAuthType) {
+-    case ENABLETYPE_BIO:
+-        strBioAuthType = "EnableAuth";
+-        break;
+-    case ENABLETYPE_SAVER:
+-        strBioAuthType = "SaverEnable";
+-        break;
+-    case ENABLETYPE_GREETER:
+-        strBioAuthType = "GreeterEnable";
+-        break;
+-    case ENABLETYPE_POLKIT:
+-        strBioAuthType = "PolkitEnable";
+-        break;
+-    case ENABLETYPE_SU:
+-        strBioAuthType = "SuEnable";
+-        break;
+-    case ENABLETYPE_SUDO:
+-        strBioAuthType = "SudoEnable";
+-        break;
+-    case ENABLETYPE_LOGIN:
+-        strBioAuthType = "LoginEnable";
+-        break;
+-    default:
+-        return false;
++            return false;
+     }
+ 
+-    //同步990旧的配置文件,然后删除
+-    if(getIs990() && (bioAuthType == ENABLETYPE_BIO)){
++    // 同步990旧的配置文件,然后删除
++    if (getIs990() && (bioAuthType == ENABLETYPE_BIO)) {
+         QString oldConfigPath = QString(OLD_990_USER_CONFIG_PATH).arg(userName);
+         QSettings oldSettings(oldConfigPath, QSettings::IniFormat);
+-        if(oldSettings.contains(strBioAuthType)){
+-            settings.setValue(strBioAuthType,oldSettings.value(strBioAuthType).toBool());
++        if (oldSettings.contains(strBioAuthType)) {
++            settings.setValue(strBioAuthType, oldSettings.value(strBioAuthType).toBool());
+             oldSettings.remove(strBioAuthType);
+             oldSettings.sync();
+         }
+     }
+     if (settings.contains(strBioAuthType)) {
+         return settings.value(strBioAuthType).toBool();
+-    }else if(getIs990() && (bioAuthType == ENABLETYPE_BIO)){
+-        //990默认为打开
++    } else if (getIs990() && (bioAuthType == ENABLETYPE_BIO)) {
++        // 990默认为打开
+         return true;
+     } else {
+         QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat);
+@@ -525,7 +557,7 @@ bool ServiceInterface::getBioAuthStatus(QString userName, int bioAuthType)
+ int ServiceInterface::getMaxFailedTimes()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("MaxFailedTimes"))
++    if (sysSettings.contains("MaxFailedTimes"))
+         return sysSettings.value("MaxFailedTimes").toInt();
+     else
+         return 3;
+@@ -534,7 +566,7 @@ int ServiceInterface::getMaxFailedTimes()
+ int ServiceInterface::getFTimeoutTimes()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("FaceTimeoutTimes"))
++    if (sysSettings.contains("FaceTimeoutTimes"))
+         return sysSettings.value("FaceTimeoutTimes").toInt();
+     else
+         return 1;
+@@ -564,7 +596,7 @@ bool ServiceInterface::getQRCodeEnable()
+ bool ServiceInterface::getDoubleAuth()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("DoubleAuth"))
++    if (sysSettings.contains("DoubleAuth"))
+         return sysSettings.value("DoubleAuth").toBool();
+     else
+         return false;
+@@ -574,7 +606,7 @@ bool ServiceInterface::getDoubleAuth()
+ bool ServiceInterface::getUserBind()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("UserBind"))
++    if (sysSettings.contains("UserBind"))
+         return sysSettings.value("UserBind").toBool();
+     else
+         return false;
+@@ -584,7 +616,7 @@ bool ServiceInterface::getUserBind()
+ bool ServiceInterface::getIsShownInControlCenter()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("isShownInControlCenter"))
++    if (sysSettings.contains("isShownInControlCenter"))
+         return sysSettings.value("isShownInControlCenter").toBool();
+     else
+         return false;
+@@ -594,7 +626,7 @@ bool ServiceInterface::getIsShownInControlCenter()
+ bool ServiceInterface::getUseFirstDevice()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("UseFirstDevice"))
++    if (sysSettings.contains("UseFirstDevice"))
+         return sysSettings.value("UseFirstDevice").toBool();
+     else
+         return false;
+@@ -604,7 +636,7 @@ bool ServiceInterface::getUseFirstDevice()
+ bool ServiceInterface::getHiddenSwitchButton()
+ {
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("HiddenSwitchButton"))
++    if (sysSettings.contains("HiddenSwitchButton"))
+         return sysSettings.value("HiddenSwitchButton").toBool();
+     else
+         return false;
+@@ -613,8 +645,9 @@ bool ServiceInterface::getHiddenSwitchButton()
+ // 获取旧版app使能值
+ int ServiceInterface::getOldAppStatus()
+ {
++    initData();
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("EnableAuthApp"))
++    if (sysSettings.contains("EnableAuthApp"))
+         return sysSettings.value("EnableAuthApp").toInt();
+     else
+         return 63;
+@@ -623,32 +656,31 @@ int ServiceInterface::getOldAppStatus()
+ void ServiceInterface::onUSBDeviceHotPlug(int drvid, int action, int deviceNum)
+ {
+     if (action > 0) {
+-        qDebug()<<"onUSBDeviceHotPlug in:"<<drvid;
++        qDebug() << "onUSBDeviceHotPlug in:" << drvid;
+         updateCommDefaultDevice(drvid);
+     }
+ }
+ 
+-//记录当前生物认证信息
+-void ServiceInterface::recordAuthDrive(QString appName,int drvid,bool insert)
++// 记录当前生物认证信息
++void ServiceInterface::recordAuthDrive(QString appName, int drvid, bool insert)
+ {
+-    if(insert){
+-        m_AuthingDriveList.insert(appName,drvid);
+-    }else{
++    if (insert) {
++        m_AuthingDriveList.insert(appName, drvid);
++    } else {
+         m_AuthingDriveList.remove(appName);
+     }
+ }
+ 
+-
+-//获取当前正在认证的应用
++// 获取当前正在认证的应用
+ QStringList ServiceInterface::getAllAuthApp()
+ {
+     return m_AuthingDriveList.keys();
+ }
+ 
+-//根据应用名称获取认证的驱动
++// 根据应用名称获取认证的驱动
+ int ServiceInterface::getAppAuthDrive(QString appName)
+ {
+-    if(m_AuthingDriveList.contains(appName)){
++    if (m_AuthingDriveList.contains(appName)) {
+         return m_AuthingDriveList.value(appName);
+     }
+     return -1;
+@@ -668,51 +700,56 @@ void ServiceInterface::SetLoginSynInformation(QString val)
+ 
+ void ServiceInterface::waitBiometricServiceStatus()
+ {
+-    qDebug()<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~` get biometric status";
+-    QDBusInterface iface("org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+-                         "org.freedesktop.systemd1.Manager",QDBusConnection::systemBus());
+-
+-    QDBusReply<QDBusObjectPath> bioPath = iface.call("GetUnit","biometric-authentication.service");
+-    if(!bioPath.isValid()){
+-        return ;
++    qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~` get biometric status";
++    QDBusInterface iface(
++        "org.freedesktop.systemd1",
++        "/org/freedesktop/systemd1",
++        "org.freedesktop.systemd1.Manager",
++        QDBusConnection::systemBus());
++
++    QDBusReply<QDBusObjectPath> bioPath = iface.call("GetUnit", "biometric-authentication.service");
++    if (!bioPath.isValid()) {
++        return;
+     }
+ 
+-    QDBusInterface bioface("org.freedesktop.systemd1", bioPath.value().path(),
+-                           "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
++    QDBusInterface bioface(
++        "org.freedesktop.systemd1",
++        bioPath.value().path(),
++        "org.freedesktop.DBus.Properties",
++        QDBusConnection::systemBus());
+     QDBusReply<QDBusVariant> sessionReply = bioface.call("Get", "org.freedesktop.systemd1.Unit", "UnitFileState");
+-    if(!sessionReply.isValid())
++    if (!sessionReply.isValid())
+         qWarning() << sessionReply.error();
+     else {
+         QString res = sessionReply.value().variant().toString();
+-        if(res == "disable")
++        if (res == "disable")
+             return;
+     }
+ 
+-    qDebug()<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   get activeState";
++    qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   get activeState";
+     int times = 0;
+-    while(times<20){
++    while (times < 20) {
+         QDBusReply<QDBusVariant> sessionReply = bioface.call("Get", "org.freedesktop.systemd1.Unit", "ActiveState");
+-        if(!sessionReply.isValid()){
++        if (!sessionReply.isValid()) {
+             qWarning() << sessionReply.error();
+-            return ;
+-        }
+-        else {
++            return;
++        } else {
+             QString res = sessionReply.value().variant().toString();
+-            if(res == "activating"){
+-                times ++;
++            if (res == "activating") {
++                times++;
+                 usleep(100000);
+-            }else{
++            } else {
+                 break;
+             }
+         }
+     }
+-    qDebug()<<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ times = "<<times;
++    qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ times = " << times;
+ }
+ 
+ void ServiceInterface::updateCommDefaultDevice(int nDriId)
+ {
+     if (!m_serviceInterface) {
+-        return ;
++        return;
+     }
+     QVariant variant;
+     QDBusArgument argument;
+@@ -721,7 +758,7 @@ void ServiceInterface::updateCommDefaultDevice(int nDriId)
+     DeviceInfoPtr deviceInfo = nullptr;
+ 
+     /* 返回值为 i -- int 和 av -- array of variant */
+-    QDBusPendingReply<int, QList<QDBusVariant> > reply = m_serviceInterface->call("GetDrvList");
++    QDBusPendingReply<int, QList<QDBusVariant>> reply = m_serviceInterface->call("GetDrvList");
+     reply.waitForFinished();
+     if (reply.isError()) {
+         qDebug() << "GUI:" << reply.error();
+@@ -730,15 +767,15 @@ void ServiceInterface::updateCommDefaultDevice(int nDriId)
+     }
+ 
+     /* 解析 DBus 返回值,reply 有两个返回值,都是 QVariant 类型 */
+-    variant = reply.argumentAt(0); /* 得到第一个返回值 */
+-    deviceCount = variant.value<int>(); /* 解封装得到设备个数 */
+-    variant = reply.argumentAt(1); /* 得到第二个返回值 */
++    variant = reply.argumentAt(0);             /* 得到第一个返回值 */
++    deviceCount = variant.value<int>();        /* 解封装得到设备个数 */
++    variant = reply.argumentAt(1);             /* 得到第二个返回值 */
+     argument = variant.value<QDBusArgument>(); /* 解封装,获取QDBusArgument对象 */
+     argument >> qlist; /* 使用运算符重载提取 argument 对象里面存储的列表对象 */
+ 
+     if (nDriId != -1) { // 指定设备接入
+         for (int i = 0; i < deviceCount; i++) {
+-            item = qlist[i]; /* 取出一个元素 */
++            item = qlist[i];          /* 取出一个元素 */
+             variant = item.variant(); /* 转为普通QVariant对象 */
+             /* 解封装得到 QDBusArgument 对象 */
+             argument = variant.value<QDBusArgument>();
+@@ -754,7 +791,7 @@ void ServiceInterface::updateCommDefaultDevice(int nDriId)
+     } else {
+         m_listDeviceInfos.clear();
+         for (int i = 0; i < deviceCount; i++) {
+-            item = qlist[i]; /* 取出一个元素 */
++            item = qlist[i];          /* 取出一个元素 */
+             variant = item.variant(); /* 转为普通QVariant对象 */
+             /* 解封装得到 QDBusArgument 对象 */
+             argument = variant.value<QDBusArgument>();
+@@ -767,65 +804,69 @@ void ServiceInterface::updateCommDefaultDevice(int nDriId)
+ 
+ void ServiceInterface::initData()
+ {
++    if (m_isDataInited) {
++        return;
++    }
++    updateCommDefaultDevice(-1);
+     // 沿用旧app enable
+     QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat);
+-    if(sysSettings.contains("EnableAuthApp") || sysSettings.contains("Functions/EnableAuthApp")) {
++    if (sysSettings.contains("EnableAuthApp") || sysSettings.contains("Functions/EnableAuthApp")) {
+         int nAppOldStatus = 0;
+         if (sysSettings.contains("Functions/EnableAuthApp")) {
+             nAppOldStatus = sysSettings.value("Functions/EnableAuthApp").toInt();
+         } else {
+             nAppOldStatus = sysSettings.value("EnableAuthApp").toInt();
+         }
+-        if ((nAppOldStatus&0x01) && !sysSettings.contains("GreeterEnable")) { // greeter
++        if ((nAppOldStatus & 0x01) && !sysSettings.contains("GreeterEnable")) { // greeter
+             sysSettings.setValue("GreeterEnable", true);
+         }
+-        if ((nAppOldStatus&0x02) && !sysSettings.contains("SaverEnable")) { // saver
++        if ((nAppOldStatus & 0x02) && !sysSettings.contains("SaverEnable")) { // saver
+             sysSettings.setValue("SaverEnable", true);
+         }
+-        if ((nAppOldStatus&0x04) && !sysSettings.contains("PolkitEnable")) { // polkit
++        if ((nAppOldStatus & 0x04) && !sysSettings.contains("PolkitEnable")) { // polkit
+             sysSettings.setValue("PolkitEnable", true);
+         }
+-        if ((nAppOldStatus&0x08) && !sysSettings.contains("SudoEnable")) { // sudo
++        if ((nAppOldStatus & 0x08) && !sysSettings.contains("SudoEnable")) { // sudo
+             sysSettings.setValue("SudoEnable", true);
+         }
+-        if ((nAppOldStatus&0x10) && !sysSettings.contains("SuEnable")) { // su
++        if ((nAppOldStatus & 0x10) && !sysSettings.contains("SuEnable")) { // su
+             sysSettings.setValue("SuEnable", true);
+         }
+-        if ((nAppOldStatus&0x20) && !sysSettings.contains("LoginEnable")) { // login
++        if ((nAppOldStatus & 0x20) && !sysSettings.contains("LoginEnable")) { // login
+             sysSettings.setValue("LoginEnable", true);
+         }
+     }
+     // 沿用旧的默认设备
+-    if(sysSettings.contains("DefaultDevice")) {
++    if (sysSettings.contains("DefaultDevice")) {
+         QString strOldDefDev = sysSettings.value("DefaultDevice").toString();
+         if (!strOldDefDev.isEmpty()) {
+             for (auto devInfo : m_listDeviceInfos) {
+                 if (devInfo && devInfo->device_shortname == strOldDefDev) {
+                     QString strBioDefType = "";
+-                    switch(devInfo->biotype) {
+-                    case BIOTYPE_FINGERPRINT:
+-                        strBioDefType = "FP_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FINGERVEIN:
+-                        strBioDefType = "FV_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_IRIS:
+-                        strBioDefType = "IR_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_FACE:
+-                        strBioDefType = "FC_DefaultDevice";
+-                        break;
+-                    case BIOTYPE_VOICEPRINT:
+-                        strBioDefType = "VP_DefaultDevice";
+-                        break;
+-                    case UNIT_GENERAL_UKEY:
+-                        strBioDefType = "GU_DefaultDevice";
+-                        break;
+-                    case REMOTE_QRCODE_TYPE:
+-                        strBioDefType = "WC_DefaultDevice";
+-                        break;
+-                    default:
+-                        break;
++                    switch (devInfo->biotype) {
++                        case BIOTYPE_FINGERPRINT:
++                            strBioDefType = "FP_DefaultDevice";
++                            break;
++                        case BIOTYPE_FINGERVEIN:
++                            strBioDefType = "FV_DefaultDevice";
++                            break;
++                        case BIOTYPE_IRIS:
++                            strBioDefType = "IR_DefaultDevice";
++                            break;
++                        case BIOTYPE_FACE:
++                            strBioDefType = "FC_DefaultDevice";
++                            break;
++                        case BIOTYPE_VOICEPRINT:
++                            strBioDefType = "VP_DefaultDevice";
++                            break;
++                        case UNIT_GENERAL_UKEY:
++                            strBioDefType = "GU_DefaultDevice";
++                            break;
++                        case REMOTE_QRCODE_TYPE:
++                            strBioDefType = "WC_DefaultDevice";
++                            break;
++                        default:
++                            break;
+                     }
+                     if (!strBioDefType.isEmpty() && !sysSettings.contains(strBioDefType)) {
+                         sysSettings.setValue(strBioDefType, strOldDefDev);
+@@ -840,30 +881,30 @@ void ServiceInterface::initData()
+     for (auto devInfo : m_listDeviceInfos) {
+         if (devInfo && devInfo->device_available > 0 && devInfo->driver_enable > 0) {
+             QString strBioDefType = "";
+-            switch(devInfo->biotype) {
+-            case BIOTYPE_FINGERPRINT:
+-                strBioDefType = "FP_DefaultDevice";
+-                break;
+-            case BIOTYPE_FINGERVEIN:
+-                strBioDefType = "FV_DefaultDevice";
+-                break;
+-            case BIOTYPE_IRIS:
+-                strBioDefType = "IR_DefaultDevice";
+-                break;
+-            case BIOTYPE_FACE:
+-                strBioDefType = "FC_DefaultDevice";
+-                break;
+-            case BIOTYPE_VOICEPRINT:
+-                strBioDefType = "VP_DefaultDevice";
+-                break;
+-            case UNIT_GENERAL_UKEY:
+-                strBioDefType = "GU_DefaultDevice";
+-                break;
+-            case REMOTE_QRCODE_TYPE:
+-                strBioDefType = "WC_DefaultDevice";
+-                break;
+-            default:
+-                break;
++            switch (devInfo->biotype) {
++                case BIOTYPE_FINGERPRINT:
++                    strBioDefType = "FP_DefaultDevice";
++                    break;
++                case BIOTYPE_FINGERVEIN:
++                    strBioDefType = "FV_DefaultDevice";
++                    break;
++                case BIOTYPE_IRIS:
++                    strBioDefType = "IR_DefaultDevice";
++                    break;
++                case BIOTYPE_FACE:
++                    strBioDefType = "FC_DefaultDevice";
++                    break;
++                case BIOTYPE_VOICEPRINT:
++                    strBioDefType = "VP_DefaultDevice";
++                    break;
++                case UNIT_GENERAL_UKEY:
++                    strBioDefType = "GU_DefaultDevice";
++                    break;
++                case REMOTE_QRCODE_TYPE:
++                    strBioDefType = "WC_DefaultDevice";
++                    break;
++                default:
++                    break;
+             }
+             if (!strBioDefType.isEmpty() && !sysSettings.contains(strBioDefType)) {
+                 sysSettings.setValue(strBioDefType, devInfo->device_shortname);
+@@ -871,11 +912,12 @@ void ServiceInterface::initData()
+         }
+     }
+     sysSettings.sync();
++    m_isDataInited = true;
+ }
+ 
+ void ServiceInterface::onBiometricDbusChanged(bool bActive)
+ {
+-    qDebug()<<"BiometricDbus:"<<bActive;
++    qDebug() << "BiometricDbus:" << bActive;
+     if (bActive) {
+         updateCommDefaultDevice(-1);
+         initData();
+@@ -884,13 +926,13 @@ void ServiceInterface::onBiometricDbusChanged(bool bActive)
+ 
+ void ServiceInterface::checkIs990()
+ {
+-    QRegExp  r1("kirin.*9.0");
++    QRegExp r1("kirin.*9.0");
+     r1.setCaseSensitivity(Qt::CaseInsensitive);
+     QRegExp r2("pangu.*m900");
+     r2.setCaseSensitivity(Qt::CaseInsensitive);
+ 
+     QFile file(PROC_CPUINFO);
+-    if(!file.exists()){
++    if (!file.exists()) {
+         is990 = false;
+     }
+     file.open(QFile::ReadOnly);
+@@ -906,133 +948,148 @@ bool ServiceInterface::getIs990()
+ 
+ QString ServiceInterface::getPublicEncrypt()
+ {
++    if (pubKey.isEmpty()) {
++        rsac.generateKeyPair(priKey, pubKey, 1024);
++    }
+     return pubKey;
+ }
+ 
+-bool ServiceInterface::sendPassword(QString username,QByteArray password)
++bool ServiceInterface::sendPassword(QString username, QByteArray password)
+ {
++    if (priKey.isEmpty()) {
++        rsac.generateKeyPair(priKey, pubKey, 1024);
++    }
+     QByteArray decryptText;
+     QByteArray encryptText;
+-    rsac.decrypt(password, decryptText, priKey);     // 解密
+-    //如果处于登录状态
++    rsac.decrypt(password, decryptText, priKey); // 解密
++    // 如果处于登录状态
+ 
+-    qDebug()<<"sendPassword"<<loginAppList.count()<<loginAppList;
+-    if(loginAppList.contains("lightdm")){
+-        qDebug()<<"login:";
++    qDebug() << "sendPassword" << loginAppList.count() << loginAppList;
++    if (loginAppList.contains("lightdm")) {
++        qDebug() << "login:";
+         isFirstLogin = false;
+-        QString publicKey = getLoginPubKey(loginAppList.value("lightdm"),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE);
++        QString publicKey
++            = getLoginPubKey(loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE);
+         rsac.encrypt(decryptText, encryptText, publicKey.toLatin1());
+-        return sendLoginPassword(loginAppList.value("lightdm"),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE,username,encryptText);
++        return sendLoginPassword(
++            loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText);
+     }
+ 
+-    //处于锁屏状态
+-    if(loginAppList.contains(username)){
+-        qDebug()<<"unlock:";
++    // 处于锁屏状态
++    if (loginAppList.contains(username)) {
++        qDebug() << "unlock:";
+         isFirstLogin = false;
+-        QString publicKey = getLoginPubKey(loginAppList.value(username),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE);
++        QString publicKey
++            = getLoginPubKey(loginAppList.value(username), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE);
+         rsac.encrypt(decryptText, encryptText, publicKey.toLatin1());
+-        return sendLoginPassword(loginAppList.value(username),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE,username,encryptText);
++        return sendLoginPassword(
++            loginAppList.value(username), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText);
+     }
+ 
+-    if(loginAppList.count()>0){
+-	qDebug()<<"login by screensaver:";
+-	isFirstLogin = false;
+-        QString publicKey = getLoginPubKey(loginAppList.value(loginAppList.firstKey()),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE);
++    if (loginAppList.count() > 0) {
++        qDebug() << "login by screensaver:";
++        isFirstLogin = false;
++        QString publicKey = getLoginPubKey(
++            loginAppList.value(loginAppList.firstKey()), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE);
+         rsac.encrypt(decryptText, encryptText, publicKey.toLatin1());
+-        return sendLoginPassword(loginAppList.value(loginAppList.firstKey()),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE,username,encryptText);
++        return sendLoginPassword(
++            loginAppList.value(loginAppList.firstKey()),
++            SCREENSAVER_DBUS_PATH,
++            SCREENSAVER_DBUS_INTERFACE,
++            username,
++            encryptText);
+     }
+ 
+-    //如果是第一次调用,则配置自动登录
+-    if(isFirstLogin){
+-        qDebug()<<"isFirstLogin:";
++    // 如果是第一次调用,则配置自动登录
++    if (isFirstLogin) {
++        qDebug() << "isFirstLogin:";
+         isFirstLogin = false;
+         hasSaveLogin = true;
+-        return handleFirstSingleLogn(username,decryptText);
++        return handleFirstSingleLogn(username, decryptText);
+     }
+ 
+     isFirstLogin = false;
+     return false;
+ }
+ 
+-bool ServiceInterface::handleFirstSingleLogn(QString username,QByteArray decryptText)
++bool ServiceInterface::handleFirstSingleLogn(QString username, QByteArray decryptText)
+ {
+-     QEventLoop loopTemp;
+-     bool ret = false;
+-     QByteArray encryptText;
+-
+-     qDebug()<<"handleFirstSingleLogn wait";
+-     QMetaObject::Connection connection = QObject::connect(this, &ServiceInterface::onLoginServicdRegisted, [&loopTemp]() {
+-         if (loopTemp.isRunning()) {
+-             loopTemp.quit();
+-         }
+-     });
+-     QTimer::singleShot(10000, &loopTemp, SLOT(quit()));
+-     loopTemp.exec();
+-     qDebug()<<"handleFirstSingleLogn finished";
+-     disconnect(connection);
+-     qDebug()<<loginAppList.count();
+-     if(loginAppList.contains("lightdm")){
+-         isFirstLogin = false;
+-         QString publicKey = getLoginPubKey(loginAppList.value("lightdm"),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE);
+-         if(publicKey.isEmpty()){
+-             qDebug()<<"get Login PubKey failed!";
+-             return false;
+-         }
+-         rsac.encrypt(decryptText, encryptText, publicKey.toLatin1());
+-         return sendLoginPassword(loginAppList.value("lightdm"),SCREENSAVER_DBUS_PATH,SCREENSAVER_DBUS_INTERFACE,username,encryptText);
+-     }
+-     return ret;
++    QEventLoop loopTemp;
++    bool ret = false;
++    QByteArray encryptText;
++
++    qDebug() << "handleFirstSingleLogn wait";
++    QMetaObject::Connection connection
++        = QObject::connect(this, &ServiceInterface::onLoginServicdRegisted, [&loopTemp]() {
++              if (loopTemp.isRunning()) {
++                  loopTemp.quit();
++              }
++          });
++    QTimer::singleShot(10000, &loopTemp, SLOT(quit()));
++    loopTemp.exec();
++    qDebug() << "handleFirstSingleLogn finished";
++    disconnect(connection);
++    qDebug() << loginAppList.count();
++    if (loginAppList.contains("lightdm")) {
++        isFirstLogin = false;
++        QString publicKey
++            = getLoginPubKey(loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE);
++        if (publicKey.isEmpty()) {
++            qDebug() << "get Login PubKey failed!";
++            return false;
++        }
++        rsac.encrypt(decryptText, encryptText, publicKey.toLatin1());
++        return sendLoginPassword(
++            loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText);
++    }
++    return ret;
+ }
+ 
+-QString  ServiceInterface::getLoginPubKey(QString service,QString path,QString interface)
++QString ServiceInterface::getLoginPubKey(QString service, QString path, QString interface)
+ {
+-    QDBusInterface iface(service,
+-                             path,
+-                             interface,
+-                             QDBusConnection::systemBus());
++    QDBusInterface iface(service, path, interface, QDBusConnection::systemBus());
+     QDBusReply<QString> stateReply = iface.call("getPublicEncrypt");
+ 
+-    if(!stateReply.isValid()){
+-        qWarning()<< "Get state error:" << stateReply.error();
+-        qDebug()<<"getPublicEncrypt failed";
++    if (!stateReply.isValid()) {
++        qWarning() << "Get state error:" << stateReply.error();
++        qDebug() << "getPublicEncrypt failed";
+         return "";
+     }
+     return stateReply.value();
+ }
+ 
+-bool ServiceInterface::sendSignalLoginFinished(QString username,bool res)
++bool ServiceInterface::sendSignalLoginFinished(QString username, bool res)
+ {
+-    qDebug()<<"sendSignalLoginFinished "<<username<<res;
+-    emit onSignalLoginFinished(username,res);
++    qDebug() << "sendSignalLoginFinished " << username << res;
++    emit onSignalLoginFinished(username, res);
+ 
+     return true;
+ }
+ 
+-bool  ServiceInterface::sendLoginPassword(QString service,QString path,QString interface,QString username,QByteArray array)
++bool ServiceInterface::sendLoginPassword(
++    QString service, QString path, QString interface, QString username, QByteArray array)
+ {
+     QEventLoop loopTemp;
+     bool ret = false;
+ 
+-    qDebug()<<"sendLoginPassword";
+-    QMetaObject::Connection connection = QObject::connect(this, &ServiceInterface::onSignalLoginFinished, [&loopTemp,&ret](QString username,bool res) {
+-        qDebug()<<"onSignalLoginFinished:"<<username<<res;
+-        ret = res;
+-        if (loopTemp.isRunning()) {
++    qDebug() << "sendLoginPassword";
++    QMetaObject::Connection connection = QObject::connect(
++        this, &ServiceInterface::onSignalLoginFinished, [&loopTemp, &ret](QString username, bool res) {
++            qDebug() << "onSignalLoginFinished:" << username << res;
++            ret = res;
++            if (loopTemp.isRunning()) {
+                 loopTemp.quit();
+-        }
+-    });
+-
+-    QDBusInterface iface(service,
+-                         path,
+-                         interface,
+-                         QDBusConnection::systemBus());
+-    QDBusReply<bool> stateReply = iface.call("sendPassword",username,array);
+-    if(!stateReply.isValid()){
++            }
++        });
++
++    QDBusInterface iface(service, path, interface, QDBusConnection::systemBus());
++    QDBusReply<bool> stateReply = iface.call("sendPassword", username, array);
++    if (!stateReply.isValid()) {
+         disconnect(connection);
+         return false;
+     }
+ 
+-    if(!stateReply.value()){
++    if (!stateReply.value()) {
+         disconnect(connection);
+         return stateReply.value();
+     }
+@@ -1044,13 +1101,14 @@ bool  ServiceInterface::sendLoginPassword(QString service,QString path,QString i
+ 
+     return ret;
+ }
++
+ QString ServiceInterface::getProcessNameFromPid(int pid)
+ {
+     QString filename = "/proc/" + QString::number(pid) + "/cmdline";
+-    qDebug()<<"filename is "<<filename;
++    qDebug() << "filename is " << filename;
+     QFile file(filename);
+-    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+-        qDebug()<<"Can't open the file!"<<endl;
++    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
++        qDebug() << "Can't open the file!" << endl;
+         return "";
+     }
+     QByteArray text = file.readAll();
+@@ -1061,18 +1119,18 @@ QString ServiceInterface::getUserNameFromUid(int uid)
+ {
+     struct passwd *pw = NULL;
+     pw = getpwuid(uid);
+-    if(pw){
++    if (pw) {
+         return QString(pw->pw_name);
+     }
+     return "";
+ }
+ 
+-void ServiceInterface::onDbusNameOwnerChanged(QString name,QString oldOwner,QString newOwner)
++void ServiceInterface::onDbusNameOwnerChanged(QString name, QString oldOwner, QString newOwner)
+ {
+-    if(newOwner.isEmpty()){
+-        for(QString str:loginAppList.keys()){
+-            if(name == loginAppList.value(str)){
+-                qDebug()<<"remove name  "<<name;
++    if (newOwner.isEmpty()) {
++        for (QString str : loginAppList.keys()) {
++            if (name == loginAppList.value(str)) {
++                qDebug() << "remove name  " << name;
+                 loginAppList.remove(str);
+             }
+         }
+@@ -1093,25 +1151,81 @@ bool ServiceInterface::registerLoginApp()
+     int uid = conn.interface()->serviceUid(msg.service()).value();
+ 
+     QString appName = getProcessNameFromPid(pid);
+-    qDebug()<<"appName = "<<appName;
++    qDebug() << "appName = " << appName;
+ 
+-    if(appName != UKUI_GREETER && appName != UKUI_SCREENSAVER){
++    if (appName != UKUI_GREETER && appName != UKUI_SCREENSAVER) {
+         return false;
+     }
+ 
+     QString appUser = getUserNameFromUid(uid);
+-    if(appUser.isEmpty())
++    if (appUser.isEmpty())
+         return false;
+ 
+-    qDebug()<<"insert "<<appUser<<serviceOwner;
+-    loginAppList.insert(appUser,serviceOwner);
++    qDebug() << "insert " << appUser << serviceOwner;
++    loginAppList.insert(appUser, serviceOwner);
+ 
+-    if(appUser == "lightdm" && hasSaveLogin){
+-        QTimer::singleShot(1000, this, [=](){
+-           emit onLoginServicdRegisted();
+-        });
++    if (appUser == "lightdm" && hasSaveLogin) {
++        QTimer::singleShot(1000, this, [=]() { emit onLoginServicdRegisted(); });
+     }
+ 
+     return true;
+ }
+ 
++int ServiceInterface::SwitchToUser(QString strUserName)
++{
++    m_willLoginUser.strUserName = strUserName;
++    m_willLoginUser.isOneKeyLogin = true;
++    Q_EMIT userChanged(m_willLoginUser);
++    return 0;
++}
++
++int ServiceInterface::SwitchToGreeterUser(QString strUserName)
++{
++    m_willLoginUser.strUserName = strUserName;
++    m_willLoginUser.isOneKeyLogin = false;
++    Q_EMIT userChanged(m_willLoginUser);
++    return 0;
++}
++
++WillLoginUserInfo ServiceInterface::getWillSwitchUser()
++{
++    return m_willLoginUser;
++}
++
++int ServiceInterface::SaveLastLoginUser(QString strUserName)
++{
++    QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat);
++    settings.beginGroup("Greeter");
++    settings.setValue("lastLoginUser", strUserName);
++    settings.endGroup();
++    settings.sync();
++    return 0;
++}
++
++QString ServiceInterface::GetLastLoginUser()
++{
++    QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat);
++    settings.beginGroup("Greeter");
++    QString lastLoginUser = settings.value("lastLoginUser").toString();
++    settings.endGroup();
++    return lastLoginUser;
++}
++
++int ServiceInterface::SaveQuickLoginUser(QString strUserName)
++{
++    QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat);
++    settings.beginGroup("Greeter");
++    settings.setValue("lastLoginUser1", strUserName);
++    settings.endGroup();
++    settings.sync();
++    return 0;
++}
++
++QString ServiceInterface::GetQuickLoginUser()
++{
++    QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat);
++    settings.beginGroup("Greeter");
++    QString lastLoginUser = settings.value("lastLoginUser1").toString();
++    settings.endGroup();
++    return lastLoginUser;
++}
+diff --git a/uniauth-backend/src/serviceinterface.h b/uniauth-backend/src/serviceinterface.h
+index 6edf7b6..05e400c 100644
+--- a/uniauth-backend/src/serviceinterface.h
++++ b/uniauth-backend/src/serviceinterface.h
+@@ -14,7 +14,7 @@
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, see <http://www.gnu.org/licenses/>.
+  *
+-**/
++ **/
+ #ifndef SERVICEINTERFACE_H
+ #define SERVICEINTERFACE_H
+ 
+@@ -31,16 +31,32 @@
+ #define DBUS_PATH "/org/ukui/Biometric"
+ #define DBUS_INTERFACE "org.ukui.Biometric"
+ 
+-enum authEnableType {
+-    ENABLETYPE_BIO,         // 全局总使能
+-    ENABLETYPE_SAVER,       // 锁屏
+-    ENABLETYPE_GREETER,     // 登录
+-    ENABLETYPE_POLKIT,      // 授权
+-    ENABLETYPE_SU,          // 暂保留
+-    ENABLETYPE_SUDO,        // 暂保留
+-    ENABLETYPE_LOGIN,       // 暂保留
++enum authEnableType
++{
++    ENABLETYPE_BIO,     // 全局总使能
++    ENABLETYPE_SAVER,   // 锁屏
++    ENABLETYPE_GREETER, // 登录
++    ENABLETYPE_POLKIT,  // 授权
++    ENABLETYPE_SU,      // 暂保留
++    ENABLETYPE_SUDO,    // 暂保留
++    ENABLETYPE_LOGIN,   // 暂保留
++};
++
++/**
++ * @brief 用户信息
++ */
++struct WillLoginUserInfo
++{
++    QString strUserName = "";
++    bool isOneKeyLogin = false;
+ };
+ 
++QDBusArgument &operator<<(QDBusArgument &arg, const WillLoginUserInfo &willLoginUserInfo);
++const QDBusArgument &operator>>(const QDBusArgument &arg, WillLoginUserInfo &willLoginUserInfo);
++QDebug operator<<(QDebug stream, const WillLoginUserInfo &willLoginUserInfo);
++
++Q_DECLARE_METATYPE(WillLoginUserInfo)
++
+ class ServiceInterface : public QObject, protected QDBusContext
+ {
+     Q_OBJECT
+@@ -55,7 +71,7 @@ public slots:
+     QString getDefaultDevice(QString userName, int bioDevType);
+     // 获取所有默认设备
+     QStringList getAllDefaultDevice(QString userName);
+-    //生物特征开关接口
++    // 生物特征开关接口
+     bool getBioAuthStatus(QString userName, int bioAuthType);
+     void setBioAuthStatus(int bioAuthType, bool status);
+     // 获取最大失败次数
+@@ -77,44 +93,95 @@ public slots:
+     // 获取是否隐藏切换按钮
+     bool getHiddenSwitchButton();
+     // 记录当前正在进行生物认证的设备
+-    void recordAuthDrive(QString appName,int drvid,bool insert);
++    void recordAuthDrive(QString appName, int drvid, bool insert);
+     // 获取当前正在进行生物认证的应用
+     QStringList getAllAuthApp();
+     // 获取当前应用在认证的驱动
+-    int	getAppAuthDrive(QString appName);
+-    //获取用户配置
++    int getAppAuthDrive(QString appName);
++    // 获取用户配置
+     QString GetUserInformation(QString username);
+-    //同步登录界面配置
++    // 同步登录界面配置
+     void SetLoginSynInformation(QString val);
+-    // 获取公钥    
++    // 获取公钥
+     QString getPublicEncrypt();
+-    //发送用户名和密码
+-    bool sendPassword(QString username,QByteArray password);
+-    //前端注册到后端接口
++    // 发送用户名和密码
++    bool sendPassword(QString username, QByteArray password);
++    // 前端注册到后端接口
+     bool registerLoginApp();
+-    //发送认证结果
+-    bool sendSignalLoginFinished(QString username,bool res);
++    // 发送认证结果
++    bool sendSignalLoginFinished(QString username, bool res);
++    /**
++     * @brief 一键切换并登录用户
++     *
++     * @param strUserName 用户名
++     * @return int 0 成功,否则失败
++     */
++    int SwitchToUser(QString strUserName);
++    /**
++     * @brief 切换到登录用户
++     *
++     * @param strUserName 用户名
++     * @return int 0 成功,否则失败
++     */
++    int SwitchToGreeterUser(QString strUserName);
++    /**
++     * @brief 获取将要登录的用户名
++     *
++     * @return WillLoginUserInfo 用户信息
++     */
++    WillLoginUserInfo getWillSwitchUser();
++    /**
++     * @brief SaveLastLoginUser 记录上一次登录成功的用户
++     * @param strUserName 用户名
++     * @return 0 成功,其他失败
++     */
++    int SaveLastLoginUser(QString strUserName);
++    /**
++     * @brief GetLastLoginUser 获取上一次登录的用户
++     * @return 用户名
++     */
++    QString GetLastLoginUser();
++    /**
++     * @brief SaveQuickLoginUser 保存下次快速登录的用户
++     * @param strUserName 用户名
++     * @return 0 成功,其他失败
++     */
++    int SaveQuickLoginUser(QString strUserName);
++    /**
++     * @brief GetQuickLoginUser 获取快速登录的用户名
++     * @return 用户名
++     */
++    QString GetQuickLoginUser();
++
+ private slots:
+     void onUSBDeviceHotPlug(int drvid, int action, int deviceNum);
+     void onBiometricDbusChanged(bool bActive);
+-    void onDbusNameOwnerChanged(QString name,QString oldOwner,QString newOwner);
++    void onDbusNameOwnerChanged(QString name, QString oldOwner, QString newOwner);
++
+ signals:
+-    //默认设备改变
++    // 默认设备改变
+     void defaultDeviceChanged(QString userName, int bioDevType, QString deviceName);
+-    //开关状态改变
++    // 开关状态改变
+     void bioAuthStatusChanged(QString userName, int type, bool status);
+-    //用户配置改变
++    // 用户配置改变
+     void updateUserInformation(QString jsonstring);
+-    //单点登录完成信号
+-    void onSignalLoginFinished(QString username,bool res);
+-    //登录服务以启动信号
++    // 单点登录完成信号
++    void onSignalLoginFinished(QString username, bool res);
++    // 登录服务以启动信号
+     void onLoginServicdRegisted();
++    /**
++     * @brief 将要登录的用户名改变
++     *
++     * @param willLoginUser 新用户信息(需对空用户名异常处理)
++     */
++    void userChanged(WillLoginUserInfo willLoginUser);
++
+ private:
+-    //设置默认设备
++    // 设置默认设备
+     void setDefaultDevice(QString userName, int bioDevType, QString deviceName);
+-    //设置通用默认设备
++    // 设置通用默认设备
+     void setCommDefaultDevice(int bioDevType, QString deviceName);
+-    //获取通用默认设备
++    // 获取通用默认设备
+     QString getCommDefaultDevice(int bioDevType);
+     // 获取旧版app使能值
+     int getOldAppStatus();
+@@ -124,34 +191,38 @@ private:
+     void updateCommDefaultDevice(int nDriId);
+     // 等待生物识别服务
+     void waitBiometricServiceStatus();
+-    //判断系统是否为990
++    // 判断系统是否为990
+     void checkIs990();
+-    //获取系统是否为990
++    // 获取系统是否为990
+     bool getIs990();
+-    //根据pid获取进程名称
++    // 根据pid获取进程名称
+     QString getProcessNameFromPid(int pid);
+-    //根据uid获取用户名
++    // 根据uid获取用户名
+     QString getUserNameFromUid(int uid);
+-    //获取登录锁屏界面的公钥
+-    QString getLoginPubKey(QString service,QString path,QString interface);
+-    //发送密码到登录锁屏界面
+-    bool sendLoginPassword(QString service,QString path,QString interface,QString username,QByteArray array);
+-    //处理首次登录逻辑
+-    bool handleFirstSingleLogn(QString username,QByteArray decryptText);
++    // 获取登录锁屏界面的公钥
++    QString getLoginPubKey(QString service, QString path, QString interface);
++    // 发送密码到登录锁屏界面
++    bool sendLoginPassword(QString service, QString path, QString interface, QString username, QByteArray array);
++    // 处理首次登录逻辑
++    bool handleFirstSingleLogn(QString username, QByteArray decryptText);
++
+ private:
+     QDBusInterface *m_serviceInterface = nullptr;
+     DeviceList m_listDeviceInfos;
+     int deviceCount = 0;
+     bool is990 = false;
+-    QMap<QString,int> m_AuthingDriveList;
++    bool m_isDataInited = false;
++    QMap<QString, int> m_AuthingDriveList;
+ 
+-    QMap<QString,QString> loginAppList;
++    QMap<QString, QString> loginAppList;
+     RSAC rsac;
+     QByteArray priKey, pubKey;
+     bool isFirstLogin = true;
+     bool hasSaveLogin = false;
+     QString savedUsername;
+     QByteArray savedPassword;
++
++    WillLoginUserInfo m_willLoginUser; /** 将登录的用户信息 */
+ };
+ 
+ #endif // SERVICEINTERFACE_H
diff -Nru ukui-biometric-auth-4.10.0.0/debian/patches/series ukui-biometric-auth-4.10.0.0/debian/patches/series
--- ukui-biometric-auth-4.10.0.0/debian/patches/series	2024-11-15 16:52:41.000000000 +0800
+++ ukui-biometric-auth-4.10.0.0/debian/patches/series	2025-02-13 20:57:03.000000000 +0800
@@ -27,3 +27,4 @@
 0027-24-fixbug.patch
 0028-25-fixbug.patch
 0029-27-fixbug.patch
+0030-update-changelog.patch