automotive-dlt
dlt_cdh_crashid.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
28 #include <stdlib.h>
29 #include <syslog.h>
30 #include <sys/procfs.h>
31 #include <sys/user.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <asm/prctl.h>
36 #include <inttypes.h>
37 
38 #include "dlt_cdh.h"
39 #include "dlt_cdh_cpuinfo.h"
40 
41 #ifdef HAS_CITYHASH_C
42 #include "city_c.h"
43 #endif
44 
45 //ARM32 specific
46 //#define REG_FRAME_POINTER 11
47 //#define REG_INSTR_POINTER 12
48 //#define REG_STACK_POINTER 13
49 //#define REG_LINK_REGISTER 14
50 //#define REG_PROC_COUNTER 15
51 
52 #ifdef HAS_CITYHASH_C
53 static cdh_status_t crashid_cityhash(proc_info_t* p_proc);
54 #endif
55 
56 cdh_status_t get_phdr_num(proc_info_t* p_proc, unsigned int p_address, int *phdr_num)
57 {
58  int i = 0;
59 
60  if (phdr_num == NULL)
61  return CDH_NOK;
62 
63  for (i = 0; i < p_proc->m_Ehdr.e_phnum; i++)
64  {
65  if (p_proc->m_pPhdr[i].p_vaddr < p_address
66  && p_proc->m_pPhdr[i].p_vaddr + p_proc->m_pPhdr[i].p_memsz > p_address)
67  {
68  *phdr_num = i;
69  return CDH_OK;
70  }
71  }
72 
73  *phdr_num = -1;
74 
75  return CDH_NOK;
76 }
77 
78 // Thanks to libunwind for the following definitions, which helps to
79 #define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
80 #define NOTE_SIZE(_hdr) (sizeof (_hdr) + ALIGN((_hdr).n_namesz, 4) + (_hdr).n_descsz)
81 
83 {
84  int found = CDH_NOK; // CDH_OK, when we find the page note associated to PID of crashed process
85  unsigned int offset = 0;
86 
87  // TODO: if no notes were found m_note_page_size was not set to 0 which leads to a crash in this loop because it is then used
88  // uninitialised here => this is an x86_64 issue
89  while (found != CDH_OK && offset < p_proc->m_note_page_size)
90  {
91  // Crash mentioned in TODO dlt_cdh_coredump.c line 163
92  ELF_Nhdr* ptr_note = (ELF_Nhdr*) (p_proc->m_Nhdr + offset);
93 
94  if (ptr_note->n_type == NT_PRSTATUS)
95  {
96  // The first PRSTATUS note is the one of the crashed thread
97  prstatus_t* prstatus = (prstatus_t*) ((char*) ptr_note + sizeof(ELF_Nhdr) + ALIGN(ptr_note->n_namesz, 4));
98 
99  p_proc->m_crashed_pid = prstatus->pr_pid;
100 
101  get_registers(prstatus, &p_proc->m_registers);
102  found = CDH_OK;
103  }
104 
105  offset += NOTE_SIZE(*ptr_note);
106  }
107 
108  return found;
109 }
110 
111 #ifdef HAS_CITYHASH_C
112 
113 cdh_status_t crashid_cityhash(proc_info_t* p_proc)
114 {
115 #define CRASHID_BUF_SIZE MAX_PROC_NAME_LENGTH+sizeof(uint64_t)
116 
117  char cityhash_in[CRASHID_BUF_SIZE];
118  uint64_t cityhash_result=0;
119  memcpy(cityhash_in, p_proc->name, MAX_PROC_NAME_LENGTH);
120  memcpy(cityhash_in+MAX_PROC_NAME_LENGTH, &p_proc->m_crashid_phase1, sizeof(uint64_t));
121 
122  cityhash_result = CityHash64(cityhash_in, CRASHID_BUF_SIZE);
123  memcpy(p_proc->m_crashid, &cityhash_result, sizeof(uint64_t));
124 
125  return CDH_OK;
126 #undef CRASHID_BUF_SIZE
127 }
128 
129 #endif // HAS_CITYHASH_C
130 
132 {
133  uint32_t final_lr = 0;
134  uint32_t final_pc = 0;
135  int pc_phnum = 0;
136  int lr_phnum = 0;
137 
138  // translate address from virtual address (process point of view) to offset in the stack memory page
139 #define ADDRESS_REBASE(__x, __phdr_num) (__x - p_proc->m_pPhdr[__phdr_num].p_vaddr)
140  // read value in the stack at position offset: +/- sizeof(), depends on stack growing upward or downward
141 #define READ_STACK_VALUE(__offset, __type) (*(__type*)(stack_page+__offset-sizeof(__type)))
142 
143  get_phdr_num(p_proc, p_proc->m_registers.pc, &pc_phnum);
144  final_pc = ADDRESS_REBASE(p_proc->m_registers.pc, pc_phnum);
145 
146  get_phdr_num(p_proc, p_proc->m_registers.lr, &lr_phnum);
147 
148  if (lr_phnum >= 0)
149  final_lr = ADDRESS_REBASE(p_proc->m_registers.lr, lr_phnum);
150 
151  p_proc->m_crashid_phase1 = p_proc->signal << 24;
152  p_proc->m_crashid_phase1 |= (uint64_t) final_lr;
153  p_proc->m_crashid_phase1 <<= 32;
154  p_proc->m_crashid_phase1 |= (uint64_t) final_pc;
155 
156 #ifdef HAS_CITYHASH_C
157  crashid_cityhash(p_proc);
158 #else
159  memcpy(p_proc->m_crashid, &p_proc->m_crashid_phase1, sizeof(uint64_t));
160 #endif
161 
162  syslog(LOG_INFO,
163  "Crash in \"%s\", thread=\"%s\", pid=%d, crashID=%"PRIx64", based on signal=%d, PC=0x%x, caller=0x%x",
164  p_proc->name,
165  p_proc->threadname,
166  p_proc->pid,
167  *((uint64_t*) p_proc->m_crashid),
168  p_proc->signal,
169  final_pc, final_lr
170  );
171 
172  return CDH_OK;
173 }
174 
176 {
177  FILE* crashid_file = NULL;
178 
179  if ((crashid_file = fopen(CRASHID_FILE, "wt")) == NULL)
180  {
181  syslog(LOG_ERR, "(pid=%d) cannot write crashid to %s: %s", p_proc->pid, CRASHID_FILE, strerror(errno));
182  return CDH_NOK;
183  }
184 
185  fprintf(crashid_file, "%"PRIx64, *(uint64_t*) p_proc->m_crashid);
186  fclose(crashid_file);
187 
188  return CDH_OK;
189 }
190 
192 {
193  if (get_crashed_registers(p_proc) != CDH_OK)
194  {
195  syslog(LOG_ERR, "registers not found in notes");
196  return CDH_NOK;
197  }
198 
199  if (create_crashid(p_proc) != CDH_OK)
200  {
201  syslog(LOG_ERR, "crashid not generated");
202  return CDH_NOK;
203  }
204 
206 
207  return CDH_OK;
208 }
209 
#define CRASHID_FILE
Definition: dlt_cdh.h:45
ELF_Ehdr m_Ehdr
Definition: dlt_cdh.h:75
pid_t m_crashed_pid
Definition: dlt_cdh.h:83
#define ALIGN(x, a)
char name[MAX_PROC_NAME_LENGTH]
Definition: dlt_cdh.h:65
unsigned char m_crashid[CRASH_ID_LEN]
Definition: dlt_cdh.h:85
int signal
Definition: dlt_cdh.h:69
uint64_t m_crashid_phase1
Definition: dlt_cdh.h:84
cdh_status_t
void get_registers(prstatus_t *prstatus, cdh_registers_t *registers)
int write_crashid_to_filesystem(proc_info_t *p_proc)
uint64 CityHash64(const char *s, size_t len)
Definition: city_c.c:233
#define MAX_PROC_NAME_LENGTH
Definition: dlt_cdh.h:43
uint64_t lr
Definition: dlt_cdh.h:59
uint64_t pc
Definition: dlt_cdh.h:57
#define ELF_Nhdr
Definition: dlt_cdh.h:53
#define NOTE_SIZE(_hdr)
pid_t pid
Definition: dlt_cdh.h:67
cdh_status_t create_crashid(proc_info_t *p_proc)
cdh_status_t get_crashed_registers(proc_info_t *p_proc)
cdh_registers_t m_registers
Definition: dlt_cdh.h:81
cdh_status_t get_phdr_num(proc_info_t *p_proc, unsigned int p_address, int *phdr_num)
char threadname[MAX_PROC_NAME_LENGTH]
Definition: dlt_cdh.h:66
cdh_status_t treat_crash_data(proc_info_t *p_proc)
char * m_Nhdr
Definition: dlt_cdh.h:77
#define ADDRESS_REBASE(__x, __phdr_num)
#define NULL
Definition: dlt_common.h:232
ELF_Phdr * m_pPhdr
Definition: dlt_cdh.h:76