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