1*490215a3Smrg //===-- sanitizer_symbolizer_libcdep.cc -----------------------------------===//
2*490215a3Smrg //
3*490215a3Smrg // This file is distributed under the University of Illinois Open Source
4*490215a3Smrg // License. See LICENSE.TXT for details.
5*490215a3Smrg //
6*490215a3Smrg //===----------------------------------------------------------------------===//
7*490215a3Smrg //
8*490215a3Smrg // This file is shared between AddressSanitizer and ThreadSanitizer
9*490215a3Smrg // run-time libraries.
10*490215a3Smrg //===----------------------------------------------------------------------===//
11*490215a3Smrg 
12*490215a3Smrg #include "sanitizer_allocator_internal.h"
13*490215a3Smrg #include "sanitizer_internal_defs.h"
14*490215a3Smrg #include "sanitizer_symbolizer_internal.h"
15*490215a3Smrg 
16*490215a3Smrg namespace __sanitizer {
17*490215a3Smrg 
GetOrInit()18*490215a3Smrg Symbolizer *Symbolizer::GetOrInit() {
19*490215a3Smrg   SpinMutexLock l(&init_mu_);
20*490215a3Smrg   if (symbolizer_)
21*490215a3Smrg     return symbolizer_;
22*490215a3Smrg   symbolizer_ = PlatformInit();
23*490215a3Smrg   CHECK(symbolizer_);
24*490215a3Smrg   return symbolizer_;
25*490215a3Smrg }
26*490215a3Smrg 
27*490215a3Smrg // See sanitizer_symbolizer_markup.cc.
28*490215a3Smrg #if !SANITIZER_SYMBOLIZER_MARKUP
29*490215a3Smrg 
ExtractToken(const char * str,const char * delims,char ** result)30*490215a3Smrg const char *ExtractToken(const char *str, const char *delims, char **result) {
31*490215a3Smrg   uptr prefix_len = internal_strcspn(str, delims);
32*490215a3Smrg   *result = (char*)InternalAlloc(prefix_len + 1);
33*490215a3Smrg   internal_memcpy(*result, str, prefix_len);
34*490215a3Smrg   (*result)[prefix_len] = '\0';
35*490215a3Smrg   const char *prefix_end = str + prefix_len;
36*490215a3Smrg   if (*prefix_end != '\0') prefix_end++;
37*490215a3Smrg   return prefix_end;
38*490215a3Smrg }
39*490215a3Smrg 
ExtractInt(const char * str,const char * delims,int * result)40*490215a3Smrg const char *ExtractInt(const char *str, const char *delims, int *result) {
41*490215a3Smrg   char *buff;
42*490215a3Smrg   const char *ret = ExtractToken(str, delims, &buff);
43*490215a3Smrg   if (buff != 0) {
44*490215a3Smrg     *result = (int)internal_atoll(buff);
45*490215a3Smrg   }
46*490215a3Smrg   InternalFree(buff);
47*490215a3Smrg   return ret;
48*490215a3Smrg }
49*490215a3Smrg 
ExtractUptr(const char * str,const char * delims,uptr * result)50*490215a3Smrg const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
51*490215a3Smrg   char *buff;
52*490215a3Smrg   const char *ret = ExtractToken(str, delims, &buff);
53*490215a3Smrg   if (buff != 0) {
54*490215a3Smrg     *result = (uptr)internal_atoll(buff);
55*490215a3Smrg   }
56*490215a3Smrg   InternalFree(buff);
57*490215a3Smrg   return ret;
58*490215a3Smrg }
59*490215a3Smrg 
ExtractTokenUpToDelimiter(const char * str,const char * delimiter,char ** result)60*490215a3Smrg const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
61*490215a3Smrg                                       char **result) {
62*490215a3Smrg   const char *found_delimiter = internal_strstr(str, delimiter);
63*490215a3Smrg   uptr prefix_len =
64*490215a3Smrg       found_delimiter ? found_delimiter - str : internal_strlen(str);
65*490215a3Smrg   *result = (char *)InternalAlloc(prefix_len + 1);
66*490215a3Smrg   internal_memcpy(*result, str, prefix_len);
67*490215a3Smrg   (*result)[prefix_len] = '\0';
68*490215a3Smrg   const char *prefix_end = str + prefix_len;
69*490215a3Smrg   if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter);
70*490215a3Smrg   return prefix_end;
71*490215a3Smrg }
72*490215a3Smrg 
SymbolizePC(uptr addr)73*490215a3Smrg SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
74*490215a3Smrg   BlockingMutexLock l(&mu_);
75*490215a3Smrg   const char *module_name;
76*490215a3Smrg   uptr module_offset;
77*490215a3Smrg   ModuleArch arch;
78*490215a3Smrg   SymbolizedStack *res = SymbolizedStack::New(addr);
79*490215a3Smrg   if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
80*490215a3Smrg                                          &arch))
81*490215a3Smrg     return res;
82*490215a3Smrg   // Always fill data about module name and offset.
83*490215a3Smrg   res->info.FillModuleInfo(module_name, module_offset, arch);
84*490215a3Smrg   for (auto &tool : tools_) {
85*490215a3Smrg     SymbolizerScope sym_scope(this);
86*490215a3Smrg     if (tool.SymbolizePC(addr, res)) {
87*490215a3Smrg       return res;
88*490215a3Smrg     }
89*490215a3Smrg   }
90*490215a3Smrg   return res;
91*490215a3Smrg }
92*490215a3Smrg 
SymbolizeData(uptr addr,DataInfo * info)93*490215a3Smrg bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
94*490215a3Smrg   BlockingMutexLock l(&mu_);
95*490215a3Smrg   const char *module_name;
96*490215a3Smrg   uptr module_offset;
97*490215a3Smrg   ModuleArch arch;
98*490215a3Smrg   if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
99*490215a3Smrg                                          &arch))
100*490215a3Smrg     return false;
101*490215a3Smrg   info->Clear();
102*490215a3Smrg   info->module = internal_strdup(module_name);
103*490215a3Smrg   info->module_offset = module_offset;
104*490215a3Smrg   info->module_arch = arch;
105*490215a3Smrg   for (auto &tool : tools_) {
106*490215a3Smrg     SymbolizerScope sym_scope(this);
107*490215a3Smrg     if (tool.SymbolizeData(addr, info)) {
108*490215a3Smrg       return true;
109*490215a3Smrg     }
110*490215a3Smrg   }
111*490215a3Smrg   return true;
112*490215a3Smrg }
113*490215a3Smrg 
GetModuleNameAndOffsetForPC(uptr pc,const char ** module_name,uptr * module_address)114*490215a3Smrg bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
115*490215a3Smrg                                              uptr *module_address) {
116*490215a3Smrg   BlockingMutexLock l(&mu_);
117*490215a3Smrg   const char *internal_module_name = nullptr;
118*490215a3Smrg   ModuleArch arch;
119*490215a3Smrg   if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name,
120*490215a3Smrg                                          module_address, &arch))
121*490215a3Smrg     return false;
122*490215a3Smrg 
123*490215a3Smrg   if (module_name)
124*490215a3Smrg     *module_name = module_names_.GetOwnedCopy(internal_module_name);
125*490215a3Smrg   return true;
126*490215a3Smrg }
127*490215a3Smrg 
Flush()128*490215a3Smrg void Symbolizer::Flush() {
129*490215a3Smrg   BlockingMutexLock l(&mu_);
130*490215a3Smrg   for (auto &tool : tools_) {
131*490215a3Smrg     SymbolizerScope sym_scope(this);
132*490215a3Smrg     tool.Flush();
133*490215a3Smrg   }
134*490215a3Smrg }
135*490215a3Smrg 
Demangle(const char * name)136*490215a3Smrg const char *Symbolizer::Demangle(const char *name) {
137*490215a3Smrg   BlockingMutexLock l(&mu_);
138*490215a3Smrg   for (auto &tool : tools_) {
139*490215a3Smrg     SymbolizerScope sym_scope(this);
140*490215a3Smrg     if (const char *demangled = tool.Demangle(name))
141*490215a3Smrg       return demangled;
142*490215a3Smrg   }
143*490215a3Smrg   return PlatformDemangle(name);
144*490215a3Smrg }
145*490215a3Smrg 
FindModuleNameAndOffsetForAddress(uptr address,const char ** module_name,uptr * module_offset,ModuleArch * module_arch)146*490215a3Smrg bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
147*490215a3Smrg                                                    const char **module_name,
148*490215a3Smrg                                                    uptr *module_offset,
149*490215a3Smrg                                                    ModuleArch *module_arch) {
150*490215a3Smrg   const LoadedModule *module = FindModuleForAddress(address);
151*490215a3Smrg   if (module == nullptr)
152*490215a3Smrg     return false;
153*490215a3Smrg   *module_name = module->full_name();
154*490215a3Smrg   *module_offset = address - module->base_address();
155*490215a3Smrg   *module_arch = module->arch();
156*490215a3Smrg   return true;
157*490215a3Smrg }
158*490215a3Smrg 
RefreshModules()159*490215a3Smrg void Symbolizer::RefreshModules() {
160*490215a3Smrg   modules_.init();
161*490215a3Smrg   fallback_modules_.fallbackInit();
162*490215a3Smrg   RAW_CHECK(modules_.size() > 0);
163*490215a3Smrg   modules_fresh_ = true;
164*490215a3Smrg }
165*490215a3Smrg 
SearchForModule(const ListOfModules & modules,uptr address)166*490215a3Smrg static const LoadedModule *SearchForModule(const ListOfModules &modules,
167*490215a3Smrg                                            uptr address) {
168*490215a3Smrg   for (uptr i = 0; i < modules.size(); i++) {
169*490215a3Smrg     if (modules[i].containsAddress(address)) {
170*490215a3Smrg       return &modules[i];
171*490215a3Smrg     }
172*490215a3Smrg   }
173*490215a3Smrg   return nullptr;
174*490215a3Smrg }
175*490215a3Smrg 
FindModuleForAddress(uptr address)176*490215a3Smrg const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
177*490215a3Smrg   bool modules_were_reloaded = false;
178*490215a3Smrg   if (!modules_fresh_) {
179*490215a3Smrg     RefreshModules();
180*490215a3Smrg     modules_were_reloaded = true;
181*490215a3Smrg   }
182*490215a3Smrg   const LoadedModule *module = SearchForModule(modules_, address);
183*490215a3Smrg   if (module) return module;
184*490215a3Smrg 
185*490215a3Smrg   // dlopen/dlclose interceptors invalidate the module list, but when
186*490215a3Smrg   // interception is disabled, we need to retry if the lookup fails in
187*490215a3Smrg   // case the module list changed.
188*490215a3Smrg #if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
189*490215a3Smrg   if (!modules_were_reloaded) {
190*490215a3Smrg     RefreshModules();
191*490215a3Smrg     module = SearchForModule(modules_, address);
192*490215a3Smrg     if (module) return module;
193*490215a3Smrg   }
194*490215a3Smrg #endif
195*490215a3Smrg 
196*490215a3Smrg   if (fallback_modules_.size()) {
197*490215a3Smrg     module = SearchForModule(fallback_modules_, address);
198*490215a3Smrg   }
199*490215a3Smrg   return module;
200*490215a3Smrg }
201*490215a3Smrg 
202*490215a3Smrg // For now we assume the following protocol:
203*490215a3Smrg // For each request of the form
204*490215a3Smrg //   <module_name> <module_offset>
205*490215a3Smrg // passed to STDIN, external symbolizer prints to STDOUT response:
206*490215a3Smrg //   <function_name>
207*490215a3Smrg //   <file_name>:<line_number>:<column_number>
208*490215a3Smrg //   <function_name>
209*490215a3Smrg //   <file_name>:<line_number>:<column_number>
210*490215a3Smrg //   ...
211*490215a3Smrg //   <empty line>
212*490215a3Smrg class LLVMSymbolizerProcess : public SymbolizerProcess {
213*490215a3Smrg  public:
LLVMSymbolizerProcess(const char * path)214*490215a3Smrg   explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
215*490215a3Smrg 
216*490215a3Smrg  private:
ReachedEndOfOutput(const char * buffer,uptr length) const217*490215a3Smrg   bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
218*490215a3Smrg     // Empty line marks the end of llvm-symbolizer output.
219*490215a3Smrg     return length >= 2 && buffer[length - 1] == '\n' &&
220*490215a3Smrg            buffer[length - 2] == '\n';
221*490215a3Smrg   }
222*490215a3Smrg 
223*490215a3Smrg   // When adding a new architecture, don't forget to also update
224*490215a3Smrg   // script/asan_symbolize.py and sanitizer_common.h.
GetArgV(const char * path_to_binary,const char * (& argv)[kArgVMax]) const225*490215a3Smrg   void GetArgV(const char *path_to_binary,
226*490215a3Smrg                const char *(&argv)[kArgVMax]) const override {
227*490215a3Smrg #if defined(__x86_64h__)
228*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=x86_64h";
229*490215a3Smrg #elif defined(__x86_64__)
230*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=x86_64";
231*490215a3Smrg #elif defined(__i386__)
232*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=i386";
233*490215a3Smrg #elif defined(__aarch64__)
234*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=arm64";
235*490215a3Smrg #elif defined(__arm__)
236*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=arm";
237*490215a3Smrg #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
238*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=powerpc64";
239*490215a3Smrg #elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
240*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=powerpc64le";
241*490215a3Smrg #elif defined(__s390x__)
242*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=s390x";
243*490215a3Smrg #elif defined(__s390__)
244*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=s390";
245*490215a3Smrg #else
246*490215a3Smrg     const char* const kSymbolizerArch = "--default-arch=unknown";
247*490215a3Smrg #endif
248*490215a3Smrg 
249*490215a3Smrg     const char *const inline_flag = common_flags()->symbolize_inline_frames
250*490215a3Smrg                                         ? "--inlining=true"
251*490215a3Smrg                                         : "--inlining=false";
252*490215a3Smrg     int i = 0;
253*490215a3Smrg     argv[i++] = path_to_binary;
254*490215a3Smrg     argv[i++] = inline_flag;
255*490215a3Smrg     argv[i++] = kSymbolizerArch;
256*490215a3Smrg     argv[i++] = nullptr;
257*490215a3Smrg   }
258*490215a3Smrg };
259*490215a3Smrg 
LLVMSymbolizer(const char * path,LowLevelAllocator * allocator)260*490215a3Smrg LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
261*490215a3Smrg     : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {}
262*490215a3Smrg 
263*490215a3Smrg // Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on
264*490215a3Smrg // Windows, so extract tokens from the right hand side first. The column info is
265*490215a3Smrg // also optional.
ParseFileLineInfo(AddressInfo * info,const char * str)266*490215a3Smrg static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
267*490215a3Smrg   char *file_line_info = 0;
268*490215a3Smrg   str = ExtractToken(str, "\n", &file_line_info);
269*490215a3Smrg   CHECK(file_line_info);
270*490215a3Smrg 
271*490215a3Smrg   if (uptr size = internal_strlen(file_line_info)) {
272*490215a3Smrg     char *back = file_line_info + size - 1;
273*490215a3Smrg     for (int i = 0; i < 2; ++i) {
274*490215a3Smrg       while (back > file_line_info && IsDigit(*back)) --back;
275*490215a3Smrg       if (*back != ':' || !IsDigit(back[1])) break;
276*490215a3Smrg       info->column = info->line;
277*490215a3Smrg       info->line = internal_atoll(back + 1);
278*490215a3Smrg       // Truncate the string at the colon to keep only filename.
279*490215a3Smrg       *back = '\0';
280*490215a3Smrg       --back;
281*490215a3Smrg     }
282*490215a3Smrg     ExtractToken(file_line_info, "", &info->file);
283*490215a3Smrg   }
284*490215a3Smrg 
285*490215a3Smrg   InternalFree(file_line_info);
286*490215a3Smrg   return str;
287*490215a3Smrg }
288*490215a3Smrg 
289*490215a3Smrg // Parses one or more two-line strings in the following format:
290*490215a3Smrg //   <function_name>
291*490215a3Smrg //   <file_name>:<line_number>[:<column_number>]
292*490215a3Smrg // Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of
293*490215a3Smrg // them use the same output format.
ParseSymbolizePCOutput(const char * str,SymbolizedStack * res)294*490215a3Smrg void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
295*490215a3Smrg   bool top_frame = true;
296*490215a3Smrg   SymbolizedStack *last = res;
297*490215a3Smrg   while (true) {
298*490215a3Smrg     char *function_name = 0;
299*490215a3Smrg     str = ExtractToken(str, "\n", &function_name);
300*490215a3Smrg     CHECK(function_name);
301*490215a3Smrg     if (function_name[0] == '\0') {
302*490215a3Smrg       // There are no more frames.
303*490215a3Smrg       InternalFree(function_name);
304*490215a3Smrg       break;
305*490215a3Smrg     }
306*490215a3Smrg     SymbolizedStack *cur;
307*490215a3Smrg     if (top_frame) {
308*490215a3Smrg       cur = res;
309*490215a3Smrg       top_frame = false;
310*490215a3Smrg     } else {
311*490215a3Smrg       cur = SymbolizedStack::New(res->info.address);
312*490215a3Smrg       cur->info.FillModuleInfo(res->info.module, res->info.module_offset,
313*490215a3Smrg                                res->info.module_arch);
314*490215a3Smrg       last->next = cur;
315*490215a3Smrg       last = cur;
316*490215a3Smrg     }
317*490215a3Smrg 
318*490215a3Smrg     AddressInfo *info = &cur->info;
319*490215a3Smrg     info->function = function_name;
320*490215a3Smrg     str = ParseFileLineInfo(info, str);
321*490215a3Smrg 
322*490215a3Smrg     // Functions and filenames can be "??", in which case we write 0
323*490215a3Smrg     // to address info to mark that names are unknown.
324*490215a3Smrg     if (0 == internal_strcmp(info->function, "??")) {
325*490215a3Smrg       InternalFree(info->function);
326*490215a3Smrg       info->function = 0;
327*490215a3Smrg     }
328*490215a3Smrg     if (0 == internal_strcmp(info->file, "??")) {
329*490215a3Smrg       InternalFree(info->file);
330*490215a3Smrg       info->file = 0;
331*490215a3Smrg     }
332*490215a3Smrg   }
333*490215a3Smrg }
334*490215a3Smrg 
335*490215a3Smrg // Parses a two-line string in the following format:
336*490215a3Smrg //   <symbol_name>
337*490215a3Smrg //   <start_address> <size>
338*490215a3Smrg // Used by LLVMSymbolizer and InternalSymbolizer.
ParseSymbolizeDataOutput(const char * str,DataInfo * info)339*490215a3Smrg void ParseSymbolizeDataOutput(const char *str, DataInfo *info) {
340*490215a3Smrg   str = ExtractToken(str, "\n", &info->name);
341*490215a3Smrg   str = ExtractUptr(str, " ", &info->start);
342*490215a3Smrg   str = ExtractUptr(str, "\n", &info->size);
343*490215a3Smrg }
344*490215a3Smrg 
SymbolizePC(uptr addr,SymbolizedStack * stack)345*490215a3Smrg bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
346*490215a3Smrg   AddressInfo *info = &stack->info;
347*490215a3Smrg   const char *buf = FormatAndSendCommand(
348*490215a3Smrg       /*is_data*/ false, info->module, info->module_offset, info->module_arch);
349*490215a3Smrg   if (buf) {
350*490215a3Smrg     ParseSymbolizePCOutput(buf, stack);
351*490215a3Smrg     return true;
352*490215a3Smrg   }
353*490215a3Smrg   return false;
354*490215a3Smrg }
355*490215a3Smrg 
SymbolizeData(uptr addr,DataInfo * info)356*490215a3Smrg bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
357*490215a3Smrg   const char *buf = FormatAndSendCommand(
358*490215a3Smrg       /*is_data*/ true, info->module, info->module_offset, info->module_arch);
359*490215a3Smrg   if (buf) {
360*490215a3Smrg     ParseSymbolizeDataOutput(buf, info);
361*490215a3Smrg     info->start += (addr - info->module_offset); // Add the base address.
362*490215a3Smrg     return true;
363*490215a3Smrg   }
364*490215a3Smrg   return false;
365*490215a3Smrg }
366*490215a3Smrg 
FormatAndSendCommand(bool is_data,const char * module_name,uptr module_offset,ModuleArch arch)367*490215a3Smrg const char *LLVMSymbolizer::FormatAndSendCommand(bool is_data,
368*490215a3Smrg                                                  const char *module_name,
369*490215a3Smrg                                                  uptr module_offset,
370*490215a3Smrg                                                  ModuleArch arch) {
371*490215a3Smrg   CHECK(module_name);
372*490215a3Smrg   const char *is_data_str = is_data ? "DATA " : "";
373*490215a3Smrg   if (arch == kModuleArchUnknown) {
374*490215a3Smrg     if (internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", is_data_str,
375*490215a3Smrg                           module_name,
376*490215a3Smrg                           module_offset) >= static_cast<int>(kBufferSize)) {
377*490215a3Smrg       Report("WARNING: Command buffer too small");
378*490215a3Smrg       return nullptr;
379*490215a3Smrg     }
380*490215a3Smrg   } else {
381*490215a3Smrg     if (internal_snprintf(buffer_, kBufferSize, "%s\"%s:%s\" 0x%zx\n",
382*490215a3Smrg                           is_data_str, module_name, ModuleArchToString(arch),
383*490215a3Smrg                           module_offset) >= static_cast<int>(kBufferSize)) {
384*490215a3Smrg       Report("WARNING: Command buffer too small");
385*490215a3Smrg       return nullptr;
386*490215a3Smrg     }
387*490215a3Smrg   }
388*490215a3Smrg   return symbolizer_process_->SendCommand(buffer_);
389*490215a3Smrg }
390*490215a3Smrg 
SymbolizerProcess(const char * path,bool use_forkpty)391*490215a3Smrg SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty)
392*490215a3Smrg     : path_(path),
393*490215a3Smrg       input_fd_(kInvalidFd),
394*490215a3Smrg       output_fd_(kInvalidFd),
395*490215a3Smrg       times_restarted_(0),
396*490215a3Smrg       failed_to_start_(false),
397*490215a3Smrg       reported_invalid_path_(false),
398*490215a3Smrg       use_forkpty_(use_forkpty) {
399*490215a3Smrg   CHECK(path_);
400*490215a3Smrg   CHECK_NE(path_[0], '\0');
401*490215a3Smrg }
402*490215a3Smrg 
IsSameModule(const char * path)403*490215a3Smrg static bool IsSameModule(const char* path) {
404*490215a3Smrg   if (const char* ProcessName = GetProcessName()) {
405*490215a3Smrg     if (const char* SymbolizerName = StripModuleName(path)) {
406*490215a3Smrg       return !internal_strcmp(ProcessName, SymbolizerName);
407*490215a3Smrg     }
408*490215a3Smrg   }
409*490215a3Smrg   return false;
410*490215a3Smrg }
411*490215a3Smrg 
SendCommand(const char * command)412*490215a3Smrg const char *SymbolizerProcess::SendCommand(const char *command) {
413*490215a3Smrg   if (failed_to_start_)
414*490215a3Smrg     return nullptr;
415*490215a3Smrg   if (IsSameModule(path_)) {
416*490215a3Smrg     Report("WARNING: Symbolizer was blocked from starting itself!\n");
417*490215a3Smrg     failed_to_start_ = true;
418*490215a3Smrg     return nullptr;
419*490215a3Smrg   }
420*490215a3Smrg   for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
421*490215a3Smrg     // Start or restart symbolizer if we failed to send command to it.
422*490215a3Smrg     if (const char *res = SendCommandImpl(command))
423*490215a3Smrg       return res;
424*490215a3Smrg     Restart();
425*490215a3Smrg   }
426*490215a3Smrg   if (!failed_to_start_) {
427*490215a3Smrg     Report("WARNING: Failed to use and restart external symbolizer!\n");
428*490215a3Smrg     failed_to_start_ = true;
429*490215a3Smrg   }
430*490215a3Smrg   return 0;
431*490215a3Smrg }
432*490215a3Smrg 
SendCommandImpl(const char * command)433*490215a3Smrg const char *SymbolizerProcess::SendCommandImpl(const char *command) {
434*490215a3Smrg   if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
435*490215a3Smrg       return 0;
436*490215a3Smrg   if (!WriteToSymbolizer(command, internal_strlen(command)))
437*490215a3Smrg       return 0;
438*490215a3Smrg   if (!ReadFromSymbolizer(buffer_, kBufferSize))
439*490215a3Smrg       return 0;
440*490215a3Smrg   return buffer_;
441*490215a3Smrg }
442*490215a3Smrg 
Restart()443*490215a3Smrg bool SymbolizerProcess::Restart() {
444*490215a3Smrg   if (input_fd_ != kInvalidFd)
445*490215a3Smrg     CloseFile(input_fd_);
446*490215a3Smrg   if (output_fd_ != kInvalidFd)
447*490215a3Smrg     CloseFile(output_fd_);
448*490215a3Smrg   return StartSymbolizerSubprocess();
449*490215a3Smrg }
450*490215a3Smrg 
ReadFromSymbolizer(char * buffer,uptr max_length)451*490215a3Smrg bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
452*490215a3Smrg   if (max_length == 0)
453*490215a3Smrg     return true;
454*490215a3Smrg   uptr read_len = 0;
455*490215a3Smrg   while (true) {
456*490215a3Smrg     uptr just_read = 0;
457*490215a3Smrg     bool success = ReadFromFile(input_fd_, buffer + read_len,
458*490215a3Smrg                                 max_length - read_len - 1, &just_read);
459*490215a3Smrg     // We can't read 0 bytes, as we don't expect external symbolizer to close
460*490215a3Smrg     // its stdout.
461*490215a3Smrg     if (!success || just_read == 0) {
462*490215a3Smrg       Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
463*490215a3Smrg       return false;
464*490215a3Smrg     }
465*490215a3Smrg     read_len += just_read;
466*490215a3Smrg     if (ReachedEndOfOutput(buffer, read_len))
467*490215a3Smrg       break;
468*490215a3Smrg     if (read_len + 1 == max_length) {
469*490215a3Smrg       Report("WARNING: Symbolizer buffer too small\n");
470*490215a3Smrg       read_len = 0;
471*490215a3Smrg       break;
472*490215a3Smrg     }
473*490215a3Smrg   }
474*490215a3Smrg   buffer[read_len] = '\0';
475*490215a3Smrg   return true;
476*490215a3Smrg }
477*490215a3Smrg 
WriteToSymbolizer(const char * buffer,uptr length)478*490215a3Smrg bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
479*490215a3Smrg   if (length == 0)
480*490215a3Smrg     return true;
481*490215a3Smrg   uptr write_len = 0;
482*490215a3Smrg   bool success = WriteToFile(output_fd_, buffer, length, &write_len);
483*490215a3Smrg   if (!success || write_len != length) {
484*490215a3Smrg     Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
485*490215a3Smrg     return false;
486*490215a3Smrg   }
487*490215a3Smrg   return true;
488*490215a3Smrg }
489*490215a3Smrg 
490*490215a3Smrg #endif  // !SANITIZER_SYMBOLIZER_MARKUP
491*490215a3Smrg 
492*490215a3Smrg }  // namespace __sanitizer
493