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"
34 #include <sys/procfs.h>
37 #define CRASH_BUS_NAME "org.tizen.system.crash"
38 #define CRASH_OBJECT_PATH "/Org/Tizen/System/Crash"
39 #define CRASH_INTERFACE_NAME CRASH_BUS_NAME
40 #define CRASH_PATH_CRASH CRASH_OBJECT_PATH"/Crash"
41 #define CRASH_INTERFACE_CRASH CRASH_INTERFACE_NAME".Crash"
42 #define PROCESS_CRASHED "ProcessCrashed"
46 #define AARCH64_REG_LR 30
54 bool legacy_notification;
67 static int _get_important_registers(int fd, struct RegInfo **reg_info)
71 if (reg_info == NULL) {
72 _E("reg_info is NULL\n");
77 struct elf_prstatus *prstatus = mmap(NULL, sizeof(struct elf_prstatus),
78 PROT_READ, MAP_SHARED, fd, 0);
79 if (prstatus == MAP_FAILED) {
80 _E("mmap error: %m\n");
84 #if (defined __i386__) || (defined __x86_64__)
86 #elif (defined __arm__) || (defined __aarch64__)
90 *reg_info = (struct RegInfo*)malloc(sizeof(struct RegInfo)*count);
91 struct RegInfo *reginfo = *reg_info;
93 if (*reg_info == NULL) {
94 _E("malloc for reg_info error: %m");
98 #if (defined __i386__) || (defined __x86_64__)
99 struct user_regs_struct *g_registers = (struct user_regs_struct*)prstatus->pr_reg;
101 #if defined(__i386__)
102 reginfo[0].name = strdup("x86.eip");
103 reginfo[0].value = (long long int)g_registers->eip;
105 reginfo[0].name = strdup("x86_64.rip");
106 reginfo[0].value = (long long int)g_registers->rip;
107 #endif // defined(__i386__)
109 if (reginfo[0].name == NULL)
112 #elif defined(__arm__)
114 struct user_regs *g_registers;
115 g_registers = (struct user_regs*)prstatus->pr_reg;
117 if ((reginfo[0].name = strdup("arm.pc")) == NULL)
119 reginfo[0].value = (long long int)g_registers->uregs[ARM_REG_PC];
120 if ((reginfo[1].name = strdup("arm.lr")) == NULL)
122 reginfo[1].value = (long long int)g_registers->uregs[ARM_REG_LR];
124 #elif defined(__aarch64__)
126 struct user_regs_struct *g_registers = (struct user_regs_struct*)prstatus->pr_reg;
128 if ((reginfo[0].name = strdup("aarch64.pc")) == NULL)
130 reginfo[0].value = (long long int)g_registers->pc;
131 if ((reginfo[1].name = strdup("aarch64.lr")) == NULL)
133 reginfo[1].value = (long long int)g_registers->regs[AARCH64_REG_LR];
135 #endif // (defined __i386__) || (defined __x86_64__)
143 munmap(prstatus, sizeof(*prstatus));
147 _E("strdup error: %m\n");
152 static GVariant *build_legacy_message_data(const struct NotifyParams *notify_params)
154 assert(notify_params);
156 return g_variant_new("(ssss)", notify_params->cmd_name, notify_params->cmd_path, notify_params->appid, notify_params->pkgid);
159 static GVariant *build_message_data(const struct NotifyParams *notify_params)
161 assert(notify_params);
163 GVariantBuilder md_builder;
164 g_variant_builder_init(&md_builder, G_VARIANT_TYPE("(sssssiia{sv})"));
166 g_variant_builder_add(&md_builder, "s", notify_params->cmd_name);
167 g_variant_builder_add(&md_builder, "s", notify_params->cmd_path);
168 g_variant_builder_add(&md_builder, "s", notify_params->appid);
169 g_variant_builder_add(&md_builder, "s", notify_params->pkgid);
170 g_variant_builder_add(&md_builder, "s", notify_params->report_path);
171 g_variant_builder_add(&md_builder, "i", notify_params->pid);
172 g_variant_builder_add(&md_builder, "i", notify_params->tid);
174 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("a{sv}"));
176 if (notify_params->signal) {
177 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("{sv}"));
178 g_variant_builder_add(&md_builder, "s", "sys.signal");
179 g_variant_builder_add(&md_builder, "v", g_variant_new_int32(notify_params->signal));
180 g_variant_builder_close(&md_builder);
183 if (notify_params->tid_comm) {
184 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("{sv}"));
185 g_variant_builder_add(&md_builder, "s", "sys.tid.comm");
186 g_variant_builder_add(&md_builder, "v", g_variant_new_string(notify_params->tid_comm));
187 g_variant_builder_close(&md_builder);
190 struct RegInfo *reg_info;
191 int regs_count = _get_important_registers(notify_params->prstatus_fd, ®_info);
194 for (int i = 0; i < regs_count; i++) {
195 g_variant_builder_open(&md_builder, G_VARIANT_TYPE("{sv}"));
197 g_variant_builder_add(&md_builder, "s", reg_info[i].name);
198 #if (defined __x86_64__) || (defined __aarch64__)
199 g_variant_builder_add(&md_builder, "v", g_variant_new_uint64(reg_info[i].value));
201 g_variant_builder_add(&md_builder, "v", g_variant_new_uint32(reg_info[i].value));
204 free(reg_info[i].name);
205 g_variant_builder_close(&md_builder);
209 g_variant_builder_close(&md_builder);
211 return g_variant_builder_end(&md_builder);
214 static bool send_notify(GDBusConnection *conn, const struct NotifyParams *notify_params)
217 GError *error = NULL;
219 GVariant *data = notify_params->legacy_notification
220 ? build_legacy_message_data(notify_params)
221 : build_message_data(notify_params);
223 _E("Error while preparing parameters");
227 g_dbus_connection_emit_signal(conn,
230 CRASH_INTERFACE_CRASH,
235 _E("Failed to emit signal: %s", error->message);
239 g_dbus_connection_flush_sync(conn, NULL, &error);
241 _E("Failed to flush connection - signal might not be delivered: %s", error->message);
252 static bool parse_cmdline(int ac, char *av[], struct NotifyParams *params)
268 FLAG_LEGACY_NOTIFICATION,
270 static const struct option options[] = {
271 { .name = "cmdline", .has_arg = required_argument, .flag = NULL, .val = FLAG_CMDLINE },
272 { .name = "cmdpath", .has_arg = required_argument, .flag = NULL, .val = FLAG_CMDPATH },
273 { .name = "pid", .has_arg = required_argument, .flag = NULL, .val = FLAG_PID },
274 { .name = "tid", .has_arg = required_argument, .flag = NULL, .val = FLAG_TID },
275 { .name = "appid", .has_arg = required_argument, .flag = NULL, .val = FLAG_APPID },
276 { .name = "pkgid", .has_arg = required_argument, .flag = NULL, .val = FLAG_PKGID },
277 { .name = "reportpath", .has_arg = required_argument, .flag = NULL, .val = FLAG_REPORTPATH },
278 { .name = "prstatus_fd", .has_arg = required_argument, .flag = NULL, .val = FLAG_PRSTATUS_FD },
279 { .name = "signal", .has_arg = required_argument, .flag = NULL, .val = FLAG_SIGNAL },
280 { .name = "tid-comm", .has_arg = required_argument, .flag = NULL, .val = FLAG_TID_COMM },
281 { .name = "legacy-sig", .has_arg = no_argument, .flag = NULL, .val = FLAG_LEGACY_NOTIFICATION },
287 val = getopt_long_only(ac, av, "", options, NULL);
289 if (FLAG_CMDLINE == val)
290 params->cmd_name = basename(optarg);
291 else if (FLAG_CMDPATH == val)
292 params->cmd_path = optarg;
293 else if (FLAG_REPORTPATH == val)
294 params->report_path = optarg;
295 else if (FLAG_PID == val)
296 params->pid = atoi(optarg);
297 else if (FLAG_TID == val)
298 params->tid = atoi(optarg);
299 else if (FLAG_APPID == val)
300 params->appid = optarg;
301 else if (FLAG_PKGID == val)
302 params->pkgid = optarg;
303 else if (FLAG_PRSTATUS_FD == val)
304 params->prstatus_fd = atoi(optarg);
305 else if (FLAG_SIGNAL == val)
306 params->signal = atoi(optarg);
307 else if (FLAG_TID_COMM == val)
308 params->tid_comm = optarg;
309 else if (FLAG_LEGACY_NOTIFICATION == val)
310 params->legacy_notification = true;
313 return params->cmd_name && params->cmd_path && params->appid && params->pkgid && params->prstatus_fd > 0;
316 static void usage(const char *const progname)
320 printf("%s --prstatus_fd N --pid PID --tid TID --cmdline CMDLINE --cmdpath CMDPATH --appid APPID --pkgid PKGID --signal SIGNALNR [--legacy-sig]\n", progname);
323 int main(int ac, char *av[])
325 struct NotifyParams params = {0, };
327 if (!parse_cmdline(ac, av, ¶ms)) {
332 GDBusConnection *conn = NULL;
336 send_notify(conn, ¶ms);