crash-stack: work around hanging up on 'D' processes 64/104564/3
authorAdrian Szyndela <adrian.s@samsung.com>
Tue, 13 Dec 2016 13:43:06 +0000 (14:43 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Thu, 15 Dec 2016 09:44:00 +0000 (10:44 +0100)
Processes in uninterruptible sleep state ('D' status in ps)
cannot be ptraced until they leave the state. To prevent
hanging up of crash-stack, we check the target process state.
If it is 'D', then we give up ptracing it, and instead
print the information from /proc/<pid>/wchan, /proc/<pid>/syscall
and /proc/<pid>/stack.

Change-Id: I82644051a5499c42db2a8e51a7af98693e8da363

src/crash-stack/crash-stack.c

index ef1814c..694f26c 100644 (file)
@@ -290,6 +290,65 @@ void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
        close(fd);
 }
 
+static int __attachable(pid_t pid)
+{
+       /* read /proc/<pid>/stat */
+       char buf[20];
+       FILE *f;
+       char status;
+
+       snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+
+       f = fopen(buf, "r");
+       if (NULL == f)
+               return -1;
+
+       /* check if status is D */
+       if (fscanf(f, "%*d %*s %c", &status) != 1)
+               return -1;
+
+       fclose(f);
+
+       return status != 'D';
+}
+
+static void __print_proc_file(pid_t pid, const char *name)
+{
+       char buf[1024];
+       FILE *f;
+       int r;
+
+       snprintf(buf, sizeof(buf), "/proc/%d/%s", pid, name);
+
+       fprintf(outputfile, "%s:\n", buf);
+
+       f = fopen(buf, "r");
+       if (NULL == f)
+       {
+               fprintf(errfile, "Failed to open %s: %m\n", buf);
+               return;
+       }
+
+       while ((r = fread(buf, 1, sizeof(buf), f)) > 0)
+       {
+               fwrite(buf, r, 1, outputfile);
+       }
+
+       fclose(f);
+
+       fprintf(outputfile, "\n");
+}
+
+static void __print_not_attachable_process_info(pid_t pid)
+{
+       fprintf(outputfile, "ERROR: can't attach to process %d - process is in uninterruptible sleep state\n", pid);
+       fprintf(outputfile, "Giving some /proc info instead:\n\n");
+       __print_proc_file(pid, "wchan");
+       fprintf(outputfile, "\n");
+       __print_proc_file(pid, "syscall");
+       __print_proc_file(pid, "stack");
+}
+
 /**
  * @brief Opens libdwfl for using with live process
  *
@@ -301,6 +360,19 @@ static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
        int status;
        pid_t stopped_pid;
 
+       status = __attachable(pid);
+       if (-1 == status)
+       {
+               fprintf(errfile, "failed to read /proc/%d/stat: %m\n", pid);
+               return NULL;
+       }
+
+       if (!status)
+       {
+               __print_not_attachable_process_info(pid);
+               return NULL;
+       }
+
        if (ptrace(PTRACE_SEIZE, tid, NULL, PTRACE_O_TRACEEXIT) != 0) {
                fprintf(errfile, "PTRACE_SEIZE failed on TID %d: %m\n", tid);
                return NULL;