--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aul/include/aul_backtrace.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+#include <linux/limits.h>
+
+#include <string>
+
+#include "aul/aul_api.h"
+#include "aul/common/log_private.hh"
+#include "aul/include/aul.h"
+
+namespace {
+
+class Backtrace {
+ public:
+ Backtrace(pid_t pid) : pid_(pid) {
+ unw_addr_space_t addr_space = unw_create_addr_space(&_UPT_accessors, 0);
+ if (!addr_space) {
+ _E("Failed to create address space");
+ return;
+ }
+
+ struct UPT_info* upt_info =
+ static_cast<struct UPT_info*>(_UPT_create(pid_));
+ if (!upt_info) {
+ _E("Failed to create UPT_info");
+ unw_destroy_addr_space(addr_space);
+ return;
+ }
+
+ addr_space_ = addr_space;
+ upt_info_ = upt_info;
+ }
+
+ ~Backtrace() {
+ if (upt_info_) _UPT_destroy(upt_info_);
+ if (addr_space_) unw_destroy_addr_space(addr_space_);
+ }
+
+ void Print() {
+ if (!upt_info_ || !addr_space_) return;
+
+ unw_cursor_t cursor;
+ if (unw_init_remote(&cursor, addr_space_, upt_info_) < 0) {
+ _E("Failed to initialize unwinding");
+ return;
+ }
+
+ fprintf(stderr, "[pid %d][Backtrace]\n", pid_);
+ uint32_t index = 0;
+ Print(cursor, index++);
+
+ while (unw_step(&cursor) > 0) Print(cursor, index++);
+
+ fflush(stderr);
+ }
+
+ private:
+ void Print(unw_cursor_t cursor, uint32_t index) {
+ char func_name[256];
+ unw_word_t pc;
+ unw_get_reg(&cursor, UNW_REG_IP, &pc);
+
+ unw_word_t offset;
+ if (!unw_get_proc_name(&cursor, func_name, sizeof(func_name), &offset)) {
+ fprintf(stderr, "[pid %d][%03u] 0x%lx: %s + 0x%lx [%s]\n", pid_, index, pc,
+ func_name, offset, GetModuleName(pc));
+ } else {
+ fprintf(stderr, "[pid %d][%03u] 0x%lx: Unknown\n", pid_, index, pc);
+ }
+ }
+
+ const char* GetModuleName(unsigned long addr) {
+ char line[PATH_MAX];
+ std::string maps_path = "/proc/" + std::to_string(pid_) + "/maps";
+ FILE* maps_file = fopen(maps_path.c_str(), "r");
+ if (!maps_file) {
+ _E("Failed to open maps file. pid=%d", pid_);
+ return "Unknown";
+ }
+
+ unsigned long start;
+ unsigned long end;
+ char perms[5];
+ char dev[6];
+ char path[PATH_MAX];
+ int inode;
+ while (fgets(line, sizeof(line), maps_file)) {
+ if (sscanf(line, "%lx-%lx %4s %*x %5s %d %s", &start, &end, perms, dev,
+ &inode, path) >= 6) {
+ if (addr >= start && addr < end) {
+ fclose(maps_file);
+ strncpy(module_name_, path, sizeof(module_name_));
+ return module_name_;
+ }
+ }
+ }
+
+ fclose(maps_file);
+ return "Unknown";
+ }
+
+ private:
+ pid_t pid_;
+ unw_addr_space_t addr_space_ = nullptr;
+ struct UPT_info* upt_info_ = nullptr;
+ char module_name_[PATH_MAX] = { 0, };
+};
+
+class Ptrace {
+ public:
+ Ptrace(pid_t pid) : pid_(pid) {}
+
+ ~Ptrace() { Detach(); }
+
+ int Attach() {
+ if (ptrace(PTRACE_ATTACH, pid_, NULL, NULL) == -1) {
+ _E("Failed to attach to process. pid=%d, errno=%d", pid_, errno);
+ return -1;
+ }
+
+ attached_ = true;
+ return 0;
+ }
+
+ bool WaitPid() {
+ int status;
+ waitpid(pid_, &status, 0);
+ if (WIFSTOPPED(status)) return true;
+
+ return false;
+ }
+
+ void PrintBacktrace() {
+ Backtrace backtrace(pid_);
+ backtrace.Print();
+ }
+
+ private:
+ void Detach() {
+ if (!attached_) return;
+
+ if (ptrace(PTRACE_DETACH, pid_, NULL, NULL) == -1) perror("ptrace DETACH");
+
+ attached_ = false;
+ }
+
+ private:
+ bool attached_ = false;
+ pid_t pid_;
+};
+
+} // namespace
+
+extern "C" API int aul_backtrace_print(pid_t pid) {
+ if (pid < 1) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ Ptrace trace(pid);
+ if (trace.Attach() != 0) return AUL_R_ERROR;
+ if (!trace.WaitPid()) return AUL_R_ERROR;
+
+ trace.PrintBacktrace();
+ return AUL_R_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUL_BACKTRACE_H__
+#define __AUL_BACKTRACE_H__
+
+#include <sys/types.h>
+
+#include <aul.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Prints backtrace information of the specified process.
+ * @param[in] pid The process ID.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #AUL_R_OK Successful
+ * @retval #AUL_R_EINVAL Invalid parameter
+ * @retval #AUL_R_ERROR General error
+ */
+int aul_backtrace_print(pid_t pid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AUL_BACKTRACE_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/aul_backtrace.h"
+
+#include <stdio.h>
+
+#include "aul_test.hh"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulBacktracePrintTest : public AulTest {
+ public:
+ AulBacktracePrintTest()
+ : AulTest("bt", "aul_backtrace_print", "bt <pid>") {}
+
+ virtual ~AulBacktracePrintTest() {}
+
+ void SetUp() override {}
+
+ void TearDown() override {}
+
+ int Test(int argc, char** argv) override {
+ if (argc < 3) {
+ Usage();
+ return -1;
+ }
+
+ if (getuid() != 0) {
+ fprintf(stderr, "Permission denied\n");
+ return -EPERM;
+ }
+
+ _D("[aul_backtrace_print test] %s", argv[2]);
+ return aul_backtrace_print(atoi(argv[2]));
+ }
+};
+
+AUL_TEST_REGISTER(AulBacktracePrintTest, bt_test);
+
+} // namespace aul_test