2 * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * Authors: Mateusz Moscicki <m.moscicki2@partner.samsung.com>
17 * Karol Lewandowski <k.lewandowsk@samsung.com>
20 #define LOG_TAG "CRASH_MANAGER"
21 #include "shared/log.h"
22 #include "dbus-util.h"
33 #include <sys/procfs.h>
36 #define CRASH_BUS_NAME "org.tizen.system.crash"
37 #define CRASH_OBJECT_PATH "/Org/Tizen/System/Crash"
38 #define CRASH_INTERFACE_NAME CRASH_BUS_NAME
39 #define CRASH_PATH_CRASH CRASH_OBJECT_PATH"/Crash"
40 #define CRASH_INTERFACE_CRASH CRASH_INTERFACE_NAME".Crash"
41 #define PROCESS_CRASHED "ProcessCrashed"
43 #define KERNEL_DEFINED_TASK_COMM_LEN 16 // from include/linux/sched.h
47 #define AARCH64_REG_LR 30
65 static int _get_important_registers(int fd, struct RegInfo **reg_info)
69 if (reg_info == NULL) {
70 _E("reg_info is NULL\n");
75 struct elf_prstatus *prstatus = mmap(NULL, sizeof(struct elf_prstatus),
76 PROT_READ, MAP_SHARED, fd, 0);
77 if (prstatus == MAP_FAILED) {
78 _E("mmap error: %m\n");
82 #if (defined __i386__) || (defined __x86_64__)
84 #elif (defined __arm__) || (defined __aarch64__)
88 *reg_info = (struct RegInfo*)malloc(sizeof(struct RegInfo)*count);
89 struct RegInfo *reginfo = *reg_info;
91 if (*reg_info == NULL) {
92 _E("malloc for reg_info error: %m");
96 #if (defined __i386__) || (defined __x86_64__)
97 struct user_regs_struct *g_registers = (struct user_regs_struct*)prstatus->pr_reg;
100 reginfo[0].name = strdup("x86.eip");
101 reginfo[0].value = (long long int)g_registers->eip;
103 reginfo[0].name = strdup("x86_64.rip");
104 reginfo[0].value = (long long int)g_registers->rip;
105 #endif // defined(__i386__)
107 if (reginfo[0].name == NULL)
110 #elif defined(__arm__)
112 struct user_regs *g_registers;
113 g_registers = (struct user_regs*)prstatus->pr_reg;
115 if ((reginfo[0].name = strdup("arm.pc")) == NULL)
117 reginfo[0].value = (long long int)g_registers->uregs[ARM_REG_PC];
118 if ((reginfo[1].name = strdup("arm.lr")) == NULL)
120 reginfo[1].value = (long long int)g_registers->uregs[ARM_REG_LR];
122 #elif defined(__aarch64__)
124 struct user_regs_struct *g_registers = (struct user_regs_struct*)prstatus->pr_reg;
126 if ((reginfo[0].name = strdup("aarch64.pc")) == NULL)
128 reginfo[0].value = (long long int)g_registers->pc;
129 if ((reginfo[1].name = strdup("aarch64.lr")) == NULL)
131 reginfo[1].value = (long long int)g_registers->regs[AARCH64_REG_LR];
133 #endif // (defined __i386__) || (defined __x86_64__)
141 munmap(prstatus, sizeof(*prstatus));
145 _E("strdup error: %m\n");
150 static GVariant* build_message_data(const struct NotifyParams *notify_params)
152 if (notify_params == NULL)
155 GVariantBuilder md_builder;
156 g_variant_builder_init(&md_builder, G_VARIANT_TYPE("(sssssiia{sv})"));
158 g_variant_builder_add(&md_builder, "s", notify_params->cmd_name);
159 g_variant_builder_add(&md_builder, "s", notify_params->cmd_path);
160 g_variant_builder_add(&md_builder, "s", notify_params->appid);
161 g_variant_builder_add(&md_builder, "s", notify_params->pkgid);
162 g_variant_builder_add(&md_builder, "s", notify_params->report_path);
163 g_variant_builder_add(&md_builder, "i", notify_params->pid);
164 g_variant_builder_add(&md_builder, "i", notify_params->tid);
166 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("a{sv}"));
168 struct RegInfo *reg_info;
169 int regs_count = _get_important_registers(notify_params->prstatus_fd, ®_info);
172 for (int i = 0; i < regs_count; i++) {
173 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("{sv}"));
175 g_variant_builder_add(&md_builder, "s", reg_info[i].name);
176 #if (defined __x86_64__) || (defined __aarch64__)
177 g_variant_builder_add(&md_builder, "v", g_variant_new_uint64(reg_info[i].value));
179 g_variant_builder_add(&md_builder, "v", g_variant_new_uint32(reg_info[i].value));
182 free(reg_info[i].name);
183 g_variant_builder_close(&md_builder);
187 g_variant_builder_close(&md_builder);
189 return g_variant_builder_end(&md_builder);
192 static bool send_notify(GDBusConnection *conn, const struct NotifyParams *notify_params)
196 GVariant *data = build_message_data(notify_params);
198 _E("Error while preparing parameters");
202 GError *error = NULL;
203 g_dbus_connection_emit_signal(conn,
206 CRASH_INTERFACE_CRASH,
211 _E("Failed to emit signal: %s", error->message);
215 g_dbus_connection_flush_sync(conn, NULL, &error);
217 _E("Failed to flush connection - signal might not be delivered: %s", error->message);
228 static bool parse_cmdline(int ac, char *av[], struct NotifyParams *params)
243 static const struct option options[] = {
244 { .name = "cmdline", .has_arg = required_argument, .flag = NULL, .val = FLAG_CMDLINE },
245 { .name = "cmdpath", .has_arg = required_argument, .flag = NULL, .val = FLAG_CMDPATH },
246 { .name = "pid", .has_arg = required_argument, .flag = NULL, .val = FLAG_PID },
247 { .name = "tid", .has_arg = required_argument, .flag = NULL, .val = FLAG_TID },
248 { .name = "appid", .has_arg = required_argument, .flag = NULL, .val = FLAG_APPID },
249 { .name = "pkgid", .has_arg = required_argument, .flag = NULL, .val = FLAG_PKGID },
250 { .name = "reportpath", .has_arg = required_argument, .flag = NULL, .val = FLAG_REPORTPATH },
251 { .name = "prstatus_fd", .has_arg = required_argument, .flag = NULL, .val = FLAG_PRSTATUS_FD },
257 val = getopt_long_only(ac, av, "", options, NULL);
259 if (FLAG_CMDLINE == val)
260 params->cmd_name = basename(optarg);
261 else if (FLAG_CMDPATH == val)
262 params->cmd_path = optarg;
263 else if (FLAG_PID == val)
264 params->pid = atoi(optarg);
265 else if (FLAG_TID == val)
266 params->tid = atoi(optarg);
267 else if (FLAG_APPID == val)
268 params->appid = optarg;
269 else if (FLAG_PKGID == val)
270 params->pkgid = optarg;
271 else if (FLAG_PRSTATUS_FD == val)
272 params->prstatus_fd = atoi(optarg);
275 return params->cmd_name && params->cmd_path && params->appid && params->pkgid && params->prstatus_fd > 0;
278 static void usage(const char *const progname)
282 printf("%s --prstatus_fd N --pid PID --tid TID --cmdline CMDLINE --cmdpath CMDPATH --appid APPID --pkgid PKGID\n", progname);
285 int main(int ac, char *av[])
287 struct NotifyParams params = {0, };
289 if (!parse_cmdline(ac, av, ¶ms)) {
294 GDBusConnection *conn = NULL;
298 send_notify(conn, ¶ms);