bloaty.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <stddef.h>
16 
17 // For some reason this isn't getting defined by zconf.h in 32-bit builds.
18 // It's very hard to figure out why. For the moment this seems to fix it,
19 // but ideally we'd have a better solution here.
20 typedef size_t z_size_t;
21 #include <zlib.h>
22 
23 #include <atomic>
24 #include <cmath>
25 #include <fstream>
26 #include <iostream>
27 #include <limits>
28 #include <map>
29 #include <memory>
30 #include <mutex>
31 #include <sstream>
32 #include <string>
33 #include <thread>
34 #include <unordered_map>
35 #include <vector>
36 
37 #include <assert.h>
38 #include <fcntl.h>
39 #include <limits.h>
40 #include <math.h>
41 #include <signal.h>
42 #include <stdlib.h>
43 #if !defined(_MSC_VER)
44 #include <sys/mman.h>
45 #include <sys/wait.h>
46 #include <unistd.h>
47 #else
48 #include <Windows.h>
49 #endif
50 #include <sys/stat.h>
51 #include <sys/types.h>
52 
53 #include "absl/debugging/internal/demangle.h"
54 #include "absl/memory/memory.h"
55 #include "absl/strings/numbers.h"
56 #include "absl/strings/string_view.h"
57 #include "absl/strings/str_join.h"
58 #include "absl/strings/substitute.h"
59 #include "google/protobuf/io/zero_copy_stream_impl.h"
60 #include "google/protobuf/text_format.h"
61 
62 #include "bloaty.h"
63 #include "bloaty.pb.h"
64 #include "re.h"
65 #include "util.h"
66 
67 using absl::string_view;
68 
69 namespace bloaty {
70 
71 // Use a global since we would have to plumb it through so many call-stacks
72 // otherwise. We would make this thread_local but that's not supported on OS X
73 // right now.
74 int verbose_level = 0;
76 
79  const char* name;
80  const char* description;
81 };
82 
84  {DataSource::kArchiveMembers, "armembers", "the .o files in a .a file"},
85  {DataSource::kCompileUnits, "compileunits",
86  "source file for the .o file (translation unit). requires debug info."},
87  {DataSource::kInputFiles, "inputfiles",
88  "the filename specified on the Bloaty command-line"},
89  {DataSource::kInlines, "inlines",
90  "source line/file where inlined code came from. requires debug info."},
91  {DataSource::kSections, "sections", "object file section"},
92  {DataSource::kSegments, "segments", "load commands in the binary"},
93  // We require that all symbols sources are >= kSymbols.
94  {DataSource::kSymbols, "symbols",
95  "symbols from symbol table (configure demangling with --demangle)"},
96  {DataSource::kRawSymbols, "rawsymbols", "unmangled symbols"},
97  {DataSource::kFullSymbols, "fullsymbols", "full demangled symbols"},
98  {DataSource::kShortSymbols, "shortsymbols", "short demangled symbols"},
99 };
100 
101 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
102 
103 const char* GetDataSourceLabel(DataSource source) {
104  for (size_t i = 0; i < ARRAY_SIZE(data_sources); i++) {
105  if (data_sources[i].number == source) {
106  return data_sources[i].name;
107  }
108  }
109  fprintf(stderr, "Unknown data source label: %d\n", static_cast<int>(source));
110  exit(1);
111  return nullptr;
112 }
113 
114 int SignOf(long val) {
115  if (val < 0) {
116  return -1;
117  } else if (val > 0) {
118  return 1;
119  } else {
120  return 0;
121  }
122 }
123 
124 void CheckedAdd(int64_t* accum, int64_t val) {
125 #if ABSL_HAVE_BUILTIN(__builtin_add_overflow)
126  if (__builtin_add_overflow(*accum, val, accum)) {
127  THROW("integer overflow");
128  }
129 #else
130  bool safe = *accum < 0
131  ? (val >= std::numeric_limits<int64_t>::max() - *accum)
132  : (val <= std::numeric_limits<int64_t>::max() - *accum);
133  if (!safe) {
134  THROW("integer overflow");
135  }
136  *accum += val;
137 #endif
138 }
139 
141  bool need_escape = false;
142 
143  for (char ch : str) {
144  if (ch == '"' || ch == ',') {
145  need_escape = true;
146  break;
147  }
148  }
149 
150  if (need_escape) {
151  std::string ret = "\"";
152  for (char ch : str) {
153  if (ch == '"') {
154  ret += "\"\"";
155  } else {
156  ret += ch;
157  }
158  }
159  ret += "\"";
160  return ret;
161  } else {
162  return std::string(str);
163  }
164 }
165 
166 extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n,
167  int* status);
168 
170  if (source != DataSource::kShortSymbols &&
171  source != DataSource::kFullSymbols) {
172  // No demangling.
173  return std::string(symbol);
174  }
175 
176  string_view demangle_from = symbol;
177  if (absl::StartsWith(demangle_from, "__Z")) {
178  demangle_from.remove_prefix(1);
179  }
180 
181  if (source == DataSource::kShortSymbols) {
182  char demangled[1024];
183  if (absl::debugging_internal::Demangle(demangle_from.data(), demangled,
184  sizeof(demangled))) {
185  return std::string(demangled);
186  } else {
187  return std::string(symbol);
188  }
189  } else if (source == DataSource::kFullSymbols) {
190  char* demangled =
191  __cxa_demangle(demangle_from.data(), NULL, NULL, NULL);
192  if (demangled) {
193  std::string ret(demangled);
194  free(demangled);
195  return ret;
196  } else {
197  return std::string(symbol);
198  }
199  } else {
200  printf("Unexpected source: %d\n", (int)source);
202  }
203 }
204 
205 
206 // NameMunger //////////////////////////////////////////////////////////////////
207 
208 void NameMunger::AddRegex(const std::string& regex, const std::string& replacement) {
209  auto reg = absl::make_unique<ReImpl>(regex);
210  regexes_.push_back(std::make_pair(std::move(reg), replacement));
211 }
212 
214  std::string name_str(name);
216 
217  for (const auto& pair : regexes_) {
218  if (ReImpl::Extract(name_str, *pair.first, pair.second, &ret)) {
219  return ret;
220  }
221  }
222 
223  return name_str;
224 }
225 
226 
227 // Rollup //////////////////////////////////////////////////////////////////////
228 
229 // A Rollup is a hierarchical tally of sizes. Its graphical representation is
230 // something like this:
231 //
232 // 93.3% 93.3% 3.02M Unmapped
233 // 38.2% 38.2% 1.16M .debug_info
234 // 23.9% 62.1% 740k .debug_str
235 // 12.1% 74.2% 374k .debug_pubnames
236 // 11.7% 86.0% 363k .debug_loc
237 // 8.9% 94.9% 275k [Other]
238 // 5.1% 100.0% 158k .debug_ranges
239 // 6.7% 100.0% 222k LOAD [R E]
240 // 61.0% 61.0% 135k .text
241 // 21.4% 82.3% 47.5k .rodata
242 // 6.2% 88.5% 13.8k .gcc_except_table
243 // 5.9% 94.4% 13.2k .eh_frame
244 // 5.6% 100.0% 12.4k [Other]
245 // 0.0% 100.0% 1.40k [Other]
246 // 100.0% 3.24M TOTAL
247 //
248 // Rollup is the generic data structure, before we apply output massaging like
249 // collapsing excess elements into "[Other]" or sorting.
250 
252 
253 class Rollup {
254  public:
255  Rollup() {}
256  Rollup(const Rollup&) = delete;
257  Rollup& operator=(const Rollup&) = delete;
258 
259  Rollup(Rollup&& other) = default;
260  Rollup& operator=(Rollup&& other) = default;
261 
262  void AddSizes(const std::vector<std::string>& names,
263  uint64_t size, bool is_vmsize) {
264  // We start at 1 to exclude the base map (see base_map_).
265  AddInternal(names, 1, size, is_vmsize);
266  }
267 
268  // Prints a graphical representation of the rollup.
269  void CreateRollupOutput(const Options& options, RollupOutput* output) const {
271  output->diff_mode_ = false;
272  }
273 
275  RollupOutput* output) const {
276  RollupRow* row = &output->toplevel_row_;
277  row->vmsize = vm_total_;
278  row->filesize = file_total_;
281  row->vmpercent = 100;
282  row->filepercent = 100;
283  output->diff_mode_ = true;
284  CreateRows(row, base, options, true);
285  }
286 
287  void SetFilterRegex(const ReImpl* regex) {
288  filter_regex_ = regex;
289  }
290 
291  // Subtract the values in "other" from this.
292  void Subtract(const Rollup& other) {
293  vm_total_ -= other.vm_total_;
294  file_total_ -= other.file_total_;
295 
296  for (const auto& other_child : other.children_) {
297  auto& child = children_[other_child.first];
298  if (child.get() == NULL) {
299  child.reset(new Rollup());
300  }
301  child->Subtract(*other_child.second);
302  }
303  }
304 
305  // Add the values in "other" from this.
306  void Add(const Rollup& other) {
307  vm_total_ += other.vm_total_;
308  file_total_ += other.file_total_;
309 
310  for (const auto& other_child : other.children_) {
311  auto& child = children_[other_child.first];
312  if (child.get() == NULL) {
313  child.reset(new Rollup());
314  }
315  child->Add(*other_child.second);
316  }
317  }
318 
319  int64_t file_total() const { return file_total_; }
321 
322  private:
327 
328  const ReImpl* filter_regex_ = nullptr;
329 
330  // Putting Rollup by value seems to work on some compilers/libs but not
331  // others.
332  typedef std::unordered_map<std::string, std::unique_ptr<Rollup>> ChildMap;
334  static Rollup* empty_;
335 
336  static Rollup* GetEmpty() {
337  if (!empty_) {
338  empty_ = new Rollup();
339  }
340  return empty_;
341  }
342 
343  // Adds "size" bytes to the rollup under the label names[i].
344  // If there are more entries names[i+1, i+2, etc] add them to sub-rollups.
345  void AddInternal(const std::vector<std::string>& names, size_t i,
346  uint64_t size, bool is_vmsize) {
347  if (filter_regex_ != nullptr) {
348  // filter_regex_ is only set in the root rollup, which checks the full
349  // label hierarchy for a match to determine whether a region should be
350  // considered.
351  bool any_matched = false;
352 
353  for (const auto& name : names) {
355  any_matched = true;
356  break;
357  }
358  }
359 
360  if (!any_matched) {
361  // Ignore this region in the rollup and don't visit sub-rollups.
362  if (is_vmsize) {
364  } else {
366  }
367  return;
368  }
369  }
370 
371  if (is_vmsize) {
373  } else {
375  }
376 
377  if (i < names.size()) {
378  auto& child = children_[names[i]];
379  if (child.get() == nullptr) {
380  child.reset(new Rollup());
381  }
382  child->AddInternal(names, i + 1, size, is_vmsize);
383  }
384  }
385 
386  static double Percent(int64_t part, int64_t whole) {
387  if (whole == 0) {
388  if (part == 0) {
389  return NAN;
390  } else if (part > 0) {
391  return INFINITY;
392  } else {
393  return -INFINITY;
394  }
395  } else {
396  return static_cast<double>(part) / static_cast<double>(whole) * 100;
397  }
398  }
399 
400  void CreateRows(RollupRow* row, const Rollup* base, const Options& options,
401  bool is_toplevel) const;
402  void SortAndAggregateRows(RollupRow* row, const Rollup* base,
403  const Options& options, bool is_toplevel) const;
404 };
405 
407  const Options& options, bool is_toplevel) const {
408  if (base) {
409  // For a diff, the percentage is a comparison against the previous size of
410  // the same label at the same level.
411  row->vmpercent = Percent(vm_total_, base->vm_total_);
412  row->filepercent = Percent(file_total_, base->file_total_);
413  }
414 
415  for (const auto& value : children_) {
416  if (value.second->vm_total_ != 0 || value.second->file_total_ != 0) {
417  row->sorted_children.emplace_back(value.first);
418  RollupRow& child_row = row->sorted_children.back();
419  child_row.vmsize = value.second->vm_total_;
420  child_row.filesize = value.second->file_total_;
421  }
422  }
423 
424  SortAndAggregateRows(row, base, options, is_toplevel);
425 }
426 
428 
430  const Options& options,
431  bool is_toplevel) const {
432  std::vector<RollupRow>& child_rows = row->sorted_children;
433 
434  // We don't want to output a solitary "[None]" or "[Unmapped]" row except at
435  // the top level.
436  if (!is_toplevel && child_rows.size() == 1 &&
437  (child_rows[0].name == "[None]" || child_rows[0].name == "[Unmapped]")) {
438  child_rows.clear();
439  }
440 
441  // We don't want to output a single row that has exactly the same size and
442  // label as the parent.
443  if (child_rows.size() == 1 && child_rows[0].name == row->name) {
444  child_rows.clear();
445  }
446 
447  if (child_rows.empty()) {
448  return;
449  }
450 
451  // First sort by magnitude.
452  for (auto& child : child_rows) {
453  switch (options.sort_by()) {
454  case Options::SORTBY_VMSIZE:
455  child.sortkey = std::abs(child.vmsize);
456  break;
457  case Options::SORTBY_FILESIZE:
458  child.sortkey = std::abs(child.filesize);
459  break;
460  case Options::SORTBY_BOTH:
461  child.sortkey =
462  std::max(std::abs(child.vmsize), std::abs(child.filesize));
463  break;
464  default:
466  }
467  }
468 
469  std::sort(child_rows.begin(), child_rows.end(), &RollupRow::Compare);
470 
471  RollupRow others_row(others_label);
472  others_row.other_count = child_rows.size() - options.max_rows_per_level();
473  others_row.name = absl::Substitute("[$0 Others]", others_row.other_count);
474  Rollup others_rollup;
475  Rollup others_base;
476 
477  // Filter out everything but the top 'row_limit'. Add rows that were filtered
478  // out to "others_row".
479  size_t i = child_rows.size() - 1;
480  while (i >= options.max_rows_per_level()) {
481  CheckedAdd(&others_row.vmsize, child_rows[i].vmsize);
482  CheckedAdd(&others_row.filesize, child_rows[i].filesize);
483  if (base) {
484  auto it = base->children_.find(child_rows[i].name);
485  if (it != base->children_.end()) {
486  CheckedAdd(&others_base.vm_total_, it->second->vm_total_);
487  CheckedAdd(&others_base.file_total_, it->second->file_total_);
488  }
489  }
490 
491  child_rows.erase(child_rows.end() - 1);
492  i--;
493  }
494 
495  if (std::abs(others_row.vmsize) > 0 || std::abs(others_row.filesize) > 0) {
496  child_rows.push_back(others_row);
497  CheckedAdd(&others_rollup.vm_total_, others_row.vmsize);
498  CheckedAdd(&others_rollup.file_total_, others_row.filesize);
499  }
500 
501  // Now sort by actual value (positive or negative).
502  for (auto& child : child_rows) {
503  switch (options.sort_by()) {
504  case Options::SORTBY_VMSIZE:
505  child.sortkey = child.vmsize;
506  break;
507  case Options::SORTBY_FILESIZE:
508  child.sortkey = child.filesize;
509  break;
510  case Options::SORTBY_BOTH:
511  if (std::abs(child.vmsize) > std::abs(child.filesize)) {
512  child.sortkey = child.vmsize;
513  } else {
514  child.sortkey = child.filesize;
515  }
516  break;
517  default:
519  }
520  }
521 
522  std::sort(child_rows.begin(), child_rows.end(), &RollupRow::Compare);
523 
524  // For a non-diff, the percentage is compared to the total size of the parent.
525  if (!base) {
526  for (auto& child_row : child_rows) {
527  child_row.vmpercent = Percent(child_row.vmsize, row->vmsize);
528  child_row.filepercent = Percent(child_row.filesize, row->filesize);
529  }
530  }
531 
532  // Recurse into sub-rows, (except "Other", which isn't a real row).
533  for (auto& child_row : child_rows) {
534  const Rollup* child_rollup;
535  const Rollup* child_base = nullptr;
536 
537  if (child_row.other_count > 0) {
538  child_rollup = &others_rollup;
539  if (base) {
540  child_base = &others_base;
541  }
542  } else {
543  auto it = children_.find(child_row.name);
544  if (it == children_.end()) {
545  THROWF("internal error, couldn't find name $0", child_row.name);
546  }
547  child_rollup = it->second.get();
548  assert(child_rollup);
549 
550  if (base) {
551  auto it = base->children_.find(child_row.name);
552  if (it == base->children_.end()) {
553  child_base = GetEmpty();
554  } else {
555  child_base = it->second.get();
556  }
557  }
558  }
559 
560  child_rollup->CreateRows(&child_row, child_base, options, false);
561  }
562 }
563 
564 
565 // RollupOutput ////////////////////////////////////////////////////////////////
566 
567 // RollupOutput represents rollup data after we have applied output massaging
568 // like collapsing excess rows into "[Other]" and sorted the output. Once the
569 // data is in this format, we can print it to the screen (or verify the output
570 // in unit tests).
571 
572 namespace {
573 
574 std::string FixedWidthString(const std::string& input, size_t size) {
575  if (input.size() < size) {
577  while (ret.size() < size) {
578  ret += " ";
579  }
580  return ret;
581  } else {
582  return input.substr(0, size);
583  }
584 }
585 
586 bool ShowFile(const OutputOptions& options) {
587  return options.show != ShowDomain::kShowVM;
588 }
589 
590 bool ShowVM(const OutputOptions& options) {
591  return options.show != ShowDomain::kShowFile;
592 }
593 
594 std::string LeftPad(const std::string& input, size_t size) {
596  while (ret.size() < size) {
597  ret = " " + ret;
598  }
599 
600  return ret;
601 }
602 
603 std::string DoubleStringPrintf(const char *fmt, double d) {
604  char buf[1024];
605  snprintf(buf, sizeof(buf), fmt, d);
606  return std::string(buf);
607 }
608 
609 std::string SiPrint(int64_t size, bool force_sign) {
610  const char *prefixes[] = {"", "Ki", "Mi", "Gi", "Ti"};
611  size_t num_prefixes = 5;
612  size_t n = 0;
613  double size_d = size;
614  while (fabs(size_d) > 1024 && n < num_prefixes - 2) {
615  size_d /= 1024;
616  n++;
617  }
618 
620 
621  if (fabs(size_d) > 100 || n == 0) {
622  ret = std::to_string(static_cast<int64_t>(size_d)) + prefixes[n];
623  if (force_sign && size > 0) {
624  ret = "+" + ret;
625  }
626  } else if (fabs(size_d) > 10) {
627  if (force_sign) {
628  ret = DoubleStringPrintf("%+0.1f", size_d) + prefixes[n];
629  } else {
630  ret = DoubleStringPrintf("%0.1f", size_d) + prefixes[n];
631  }
632  } else {
633  if (force_sign) {
634  ret = DoubleStringPrintf("%+0.2f", size_d) + prefixes[n];
635  } else {
636  ret = DoubleStringPrintf("%0.2f", size_d) + prefixes[n];
637  }
638  }
639 
640  return LeftPad(ret, 7);
641 }
642 
643 std::string PercentString(double percent, bool diff_mode) {
644  if (diff_mode) {
645  if (percent == 0 || std::isnan(percent)) {
646  return " [ = ]";
647  } else if (percent == -100) {
648  return " [DEL]";
649  } else if (std::isinf(percent)) {
650  return " [NEW]";
651  } else {
652  // We want to keep this fixed-width even if the percent is very large.
654  if (percent > 1000) {
655  int digits = log10(percent) - 1;
656  str = DoubleStringPrintf("%+2.0f", percent / pow(10, digits)) + "e" +
657  std::to_string(digits) + "%";
658  } else if (percent > 10) {
659  str = DoubleStringPrintf("%+4.0f%%", percent);
660  } else {
661  str = DoubleStringPrintf("%+5.1F%%", percent);
662  }
663 
664  return LeftPad(str, 6);
665  }
666  } else {
667  return DoubleStringPrintf("%5.1F%%", percent);
668  }
669 }
670 
671 } // namespace
672 
673 void RollupOutput::Print(const OutputOptions& options, std::ostream* out) {
674  if (!source_names_.empty()) {
675  switch (options.output_format) {
678  break;
680  PrintToCSV(out, /*tabs=*/false);
681  break;
683  PrintToCSV(out, /*tabs=*/true);
684  break;
685  default:
687  }
688  }
689 
690  if (!disassembly_.empty()) {
691  *out << disassembly_;
692  }
693 }
694 
696  const OutputOptions& options,
697  std::ostream* out) const {
698  if (&row != &toplevel_row_) {
699  // Avoid printing this row if it is only zero.
700  // This can happen when using --domain if the row is zero for this domain.
701  if ((!ShowFile(options) && row.vmsize == 0) ||
702  (!ShowVM(options) && row.filesize == 0)) {
703  return;
704  }
705  }
706 
707  *out << FixedWidthString("", indent) << " ";
708 
709  if (ShowFile(options)) {
710  *out << PercentString(row.filepercent, diff_mode_) << " "
711  << SiPrint(row.filesize, diff_mode_) << " ";
712  }
713 
714  if (ShowVM(options)) {
715  *out << PercentString(row.vmpercent, diff_mode_) << " "
716  << SiPrint(row.vmsize, diff_mode_) << " ";
717  }
718 
719  *out << " " << row.name << "\n";
720 }
721 
723  if (a == b) {
724  return true;
725  }
726 
727  if (absl::EndsWith(b, a + "]") || absl::EndsWith(a, b + "]")) {
728  return true;
729  }
730 
731  return false;
732 }
733 
735  const OutputOptions& options,
736  std::ostream* out) const {
737  // Rows are printed before their sub-rows.
739 
740  if (!row.vmsize && !row.filesize) {
741  return;
742  }
743 
744  if (row.sorted_children.size() == 1 &&
745  row.sorted_children[0].sorted_children.size() == 0 &&
746  IsSame(row.name, row.sorted_children[0].name)) {
747  return;
748  }
749 
750  for (const auto& child : row.sorted_children) {
752  }
753 }
754 
756  std::ostream* out) const {
757  if (ShowFile(options)) {
758  *out << " FILE SIZE ";
759  }
760 
761  if (ShowVM(options)) {
762  *out << " VM SIZE ";
763  }
764 
765  *out << "\n";
766 
767  if (ShowFile(options)) {
768  *out << " -------------- ";
769  }
770 
771  if (ShowVM(options)) {
772  *out << " -------------- ";
773  }
774 
775  *out << "\n";
776 
777  for (const auto& child : toplevel_row_.sorted_children) {
779  }
780 
781  // The "TOTAL" row comes after all other rows.
783 
784  uint64_t file_filtered = 0;
785  uint64_t vm_filtered = 0;
786  if (ShowFile(options)) {
787  file_filtered = toplevel_row_.filtered_filesize;
788  }
789  if (ShowVM(options)) {
790  vm_filtered = toplevel_row_.filtered_vmsize;
791  }
792 
793  if (vm_filtered == 0 && file_filtered == 0) {
794  return;
795  }
796 
797  *out << "Filtering enabled (source_filter); omitted";
798 
799  if (file_filtered > 0 && vm_filtered > 0) {
800  *out << " file =" << SiPrint(file_filtered, /*force_sign=*/false)
801  << ", vm =" << SiPrint(vm_filtered, /*force_sign=*/false);
802  } else if (file_filtered > 0) {
803  *out << SiPrint(file_filtered, /*force_sign=*/false);
804  } else {
805  *out << SiPrint(vm_filtered, /*force_sign=*/false);
806  }
807 
808  *out << " of entries\n";
809 }
810 
812  std::vector<std::string> parent_labels,
813  std::ostream* out, bool tabs) const {
814  while (parent_labels.size() < source_names_.size()) {
815  // If this label had no data at this level, append an empty string.
816  parent_labels.push_back("");
817  }
818 
819  parent_labels.push_back(std::to_string(row.vmsize));
820  parent_labels.push_back(std::to_string(row.filesize));
821 
822  std::string sep = tabs ? "\t" : ",";
823  *out << absl::StrJoin(parent_labels, sep) << "\n";
824 }
825 
827  std::vector<std::string> parent_labels,
828  std::ostream* out, bool tabs) const {
829  if (tabs) {
830  parent_labels.push_back(row.name);
831  } else {
832  parent_labels.push_back(CSVEscape(row.name));
833  }
834 
835  if (row.sorted_children.size() > 0) {
836  for (const auto& child_row : row.sorted_children) {
837  PrintTreeToCSV(child_row, parent_labels, out, tabs);
838  }
839  } else {
840  PrintRowToCSV(row, parent_labels, out, tabs);
841  }
842 }
843 
844 void RollupOutput::PrintToCSV(std::ostream* out, bool tabs) const {
845  std::vector<std::string> names(source_names_);
846  names.push_back("vmsize");
847  names.push_back("filesize");
848  std::string sep = tabs ? "\t" : ",";
849  *out << absl::StrJoin(names, sep) << "\n";
850  for (const auto& child_row : toplevel_row_.sorted_children) {
851  PrintTreeToCSV(child_row, std::vector<std::string>(), out, tabs);
852  }
853 }
854 
855 // RangeMap ////////////////////////////////////////////////////////////////////
856 
858 
859 
860 // MmapInputFile ///////////////////////////////////////////////////////////////
861 
862 #if !defined(_MSC_VER)
863 class MmapInputFile : public InputFile {
864  public:
866  MmapInputFile(const MmapInputFile&) = delete;
867  MmapInputFile& operator=(const MmapInputFile&) = delete;
868  ~MmapInputFile() override;
869 };
870 
871 
873  public:
874  FileDescriptor(int fd) : fd_(fd) {}
875 
877  if (fd_ >= 0 && close(fd_) < 0) {
878  fprintf(stderr, "bloaty: error calling close(): %s\n", strerror(errno));
879  }
880  }
881 
882  int fd() { return fd_; }
883 
884  private:
885  int fd_;
886 };
887 
889  : InputFile(filename) {
890  FileDescriptor fd(open(filename.c_str(), O_RDONLY));
891  struct stat buf;
892  const char *map;
893 
894  if (fd.fd() < 0) {
895  THROWF("couldn't open file '$0': $1", filename, strerror(errno));
896  }
897 
898  if (fstat(fd.fd(), &buf) < 0) {
899  THROWF("couldn't stat file '$0': $1", filename, strerror(errno));
900  }
901 
902  map = static_cast<char*>(
903  mmap(nullptr, buf.st_size, PROT_READ, MAP_SHARED, fd.fd(), 0));
904 
905  if (map == MAP_FAILED) {
906  THROWF("couldn't mmap file '$0': $1", filename, strerror(errno));
907  }
908 
909  data_ = string_view(map, buf.st_size);
910 }
911 
913  if (data_.data() != nullptr &&
914  munmap(const_cast<char*>(data_.data()), data_.size()) != 0) {
915  fprintf(stderr, "bloaty: error calling munmap(): %s\n", strerror(errno));
916  }
917 }
918 
919 std::unique_ptr<InputFile> MmapInputFileFactory::OpenFile(
920  const std::string& filename) const {
921  return absl::make_unique<MmapInputFile>(filename);
922 }
923 
924 #else // !_MSC_VER
925 
926 // MmapInputFile ///////////////////////////////////////////////////////////////
927 
928 class Win32MMapInputFile : public InputFile {
929  public:
930  Win32MMapInputFile(const std::string& filename);
931  Win32MMapInputFile(const Win32MMapInputFile&) = delete;
932  Win32MMapInputFile& operator=(const Win32MMapInputFile&) = delete;
933  ~Win32MMapInputFile() override;
934 };
935 
936 class Win32Handle {
937  public:
938  Win32Handle(HANDLE h) : h_(h) {}
939 
940  ~Win32Handle() {
941  if (h_ && h_ != INVALID_HANDLE_VALUE && !CloseHandle(h_)) {
942  fprintf(stderr, "bloaty: error calling CloseHandle(): %d\n",
943  GetLastError());
944  }
945  }
946 
947  HANDLE h() { return h_; }
948 
949  private:
950  HANDLE h_;
951 };
952 
953 Win32MMapInputFile::Win32MMapInputFile(const std::string& filename)
954  : InputFile(filename) {
955  Win32Handle fd(::CreateFileA(filename.c_str(), FILE_GENERIC_READ,
956  FILE_SHARE_READ, NULL, OPEN_EXISTING,
957  FILE_ATTRIBUTE_NORMAL, NULL));
958  LARGE_INTEGER li = {};
959  const char* map;
960 
961  if (fd.h() == INVALID_HANDLE_VALUE) {
962  THROWF("couldn't open file '$0': $1", filename, ::GetLastError());
963  }
964 
965  if (!::GetFileSizeEx(fd.h(), &li)) {
966  THROWF("couldn't stat file '$0': $1", filename, ::GetLastError());
967  }
968 
969  Win32Handle mapfd(
970  ::CreateFileMappingA(fd.h(), NULL, PAGE_READONLY, 0, 0, nullptr));
971  if (!mapfd.h()) {
972  THROWF("couldn't create file mapping '$0': $1", filename, ::GetLastError());
973  }
974 
975  map = static_cast<char*>(::MapViewOfFile(mapfd.h(), FILE_MAP_READ, 0, 0, 0));
976  if (!map) {
977  THROWF("couldn't MapViewOfFile file '$0': $1", filename, ::GetLastError());
978  }
979 
980  data_ = string_view(map, li.QuadPart);
981 }
982 
983 Win32MMapInputFile::~Win32MMapInputFile() {
984  if (data_.data() != nullptr && !::UnmapViewOfFile(data_.data())) {
985  fprintf(stderr, "bloaty: error calling UnmapViewOfFile(): %d\n",
986  ::GetLastError());
987  }
988 }
989 
990 std::unique_ptr<InputFile> MmapInputFileFactory::OpenFile(
991  const std::string& filename) const {
992  return absl::make_unique<Win32MMapInputFile>(filename);
993 }
994 
995 #endif
996 
997 // RangeSink ///////////////////////////////////////////////////////////////////
998 
1000  DataSource data_source, const DualMap *translator,
1002  : file_(file), options_(options), data_source_(data_source),
1003  translator_(translator), arena_(arena) {}
1004 
1006 
1009 
1011  return options_.verbose_level() > 1 ||
1012  (options_.has_debug_vmaddr() && options_.debug_vmaddr() >= vmaddr &&
1013  options_.debug_vmaddr() < (vmaddr + vmsize));
1014 }
1015 
1017  return options_.verbose_level() > 1 ||
1018  (options_.has_debug_fileoff() && options_.debug_fileoff() >= fileoff &&
1019  options_.debug_fileoff() < (fileoff + filesize));
1020 }
1021 
1023  if (vmsize == RangeMap::kUnknownSize) {
1024  vmsize = UINT64_MAX - vmaddr;
1025  }
1026 
1027  if (vmaddr + vmsize < vmaddr) {
1028  THROWF("Overflow in vm range, vmaddr=$0, vmsize=$1", vmaddr, vmsize);
1029  }
1030 
1031  if (ContainsVerboseVMAddr(vmaddr, vmsize)) {
1032  return true;
1033  }
1034 
1035  if (translator_ && options_.has_debug_fileoff()) {
1036  RangeMap vm_map;
1037  RangeMap file_map;
1038  bool contains = false;
1039  vm_map.AddRangeWithTranslation(vmaddr, vmsize, "", translator_->vm_map,
1040  false, &file_map);
1041  file_map.ForEachRange(
1042  [this, &contains](uint64_t fileoff, uint64_t filesize) {
1043  if (ContainsVerboseFileOffset(fileoff, filesize)) {
1044  contains = true;
1045  }
1046  });
1047  return contains;
1048  }
1049 
1050  return false;
1051 }
1052 
1054  if (filesize == RangeMap::kUnknownSize) {
1055  filesize = UINT64_MAX - fileoff;
1056  }
1057 
1058  if (fileoff + filesize < fileoff) {
1059  THROWF("Overflow in file range, fileoff=$0, filesize=$1", fileoff,
1060  filesize);
1061  }
1062 
1063  if (ContainsVerboseFileOffset(fileoff, filesize)) {
1064  return true;
1065  }
1066 
1067  if (translator_ && options_.has_debug_vmaddr()) {
1068  RangeMap vm_map;
1069  RangeMap file_map;
1070  bool contains = false;
1071  file_map.AddRangeWithTranslation(fileoff, filesize, "",
1072  translator_->file_map, false, &vm_map);
1073  vm_map.ForEachRange([this, &contains](uint64_t vmaddr, uint64_t vmsize) {
1074  if (ContainsVerboseVMAddr(vmaddr, vmsize)) {
1075  contains = true;
1076  }
1077  });
1078  return contains;
1079  }
1080 
1081  return false;
1082 }
1083 
1085  outputs_.push_back(std::make_pair(map, munger));
1086 }
1087 
1088 void RangeSink::AddFileRange(const char* analyzer, string_view name,
1089  uint64_t fileoff, uint64_t filesize) {
1090  bool verbose = IsVerboseForFileRange(fileoff, filesize);
1091  if (verbose) {
1092  printf("[%s, %s] AddFileRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
1093  GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
1094  name.data(), fileoff, filesize);
1095  }
1096  for (auto& pair : outputs_) {
1097  const std::string label = pair.second->Munge(name);
1098  if (translator_) {
1099  bool ok = pair.first->file_map.AddRangeWithTranslation(
1100  fileoff, filesize, label, translator_->file_map, verbose,
1101  &pair.first->vm_map);
1102  if (!ok) {
1103  WARN("File range ($0, $1) for label $2 extends beyond base map",
1104  fileoff, filesize, name);
1105  }
1106  } else {
1107  pair.first->file_map.AddRange(fileoff, filesize, label);
1108  }
1109  }
1110 }
1111 
1112 void RangeSink::AddFileRangeForVMAddr(const char* analyzer,
1113  uint64_t label_from_vmaddr,
1114  string_view file_range) {
1115  uint64_t file_offset = file_range.data() - file_->data().data();
1116  bool verbose = IsVerboseForFileRange(file_offset, file_range.size());
1117  if (verbose) {
1118  printf("[%s, %s] AddFileRangeForVMAddr(%" PRIx64 ", [%" PRIx64 ", %zx])\n",
1119  GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr,
1120  file_offset, file_range.size());
1121  }
1122  assert(translator_);
1123  for (auto& pair : outputs_) {
1125  if (pair.first->vm_map.TryGetLabel(label_from_vmaddr, &label)) {
1126  bool ok = pair.first->file_map.AddRangeWithTranslation(
1127  file_offset, file_range.size(), label, translator_->file_map, verbose,
1128  &pair.first->vm_map);
1129  if (!ok) {
1130  WARN("File range ($0, $1) for label $2 extends beyond base map",
1131  file_offset, file_range.size(), label);
1132  }
1133  } else if (verbose_level > 1) {
1134  printf("No label found for vmaddr %" PRIx64 "\n", label_from_vmaddr);
1135  }
1136  }
1137 }
1138 
1139 void RangeSink::AddFileRangeForFileRange(const char* analyzer,
1140  absl::string_view from_file_range,
1141  absl::string_view file_range) {
1142  uint64_t file_offset = file_range.data() - file_->data().data();
1143  uint64_t from_file_offset = from_file_range.data() - file_->data().data();
1144  bool verbose = IsVerboseForFileRange(file_offset, file_range.size());
1145  if (verbose) {
1146  printf("[%s, %s] AddFileRangeForFileRange([%" PRIx64 ", %zx], [%" PRIx64
1147  ", %zx])\n",
1148  GetDataSourceLabel(data_source_), analyzer, from_file_offset,
1149  from_file_range.size(), file_offset, file_range.size());
1150  }
1151  assert(translator_);
1152  for (auto& pair : outputs_) {
1154  if (pair.first->file_map.TryGetLabelForRange(
1155  from_file_offset, from_file_range.size(), &label)) {
1156  bool ok = pair.first->file_map.AddRangeWithTranslation(
1157  file_offset, file_range.size(), label, translator_->file_map, verbose,
1158  &pair.first->vm_map);
1159  if (!ok) {
1160  WARN("File range ($0, $1) for label $2 extends beyond base map",
1161  file_offset, file_range.size(), label);
1162  }
1163  } else if (verbose_level > 1) {
1164  printf("No label found for file range [%" PRIx64 ", %zx]\n",
1165  from_file_offset, from_file_range.size());
1166  }
1167  }
1168 }
1169 
1170 void RangeSink::AddVMRangeForVMAddr(const char* analyzer,
1171  uint64_t label_from_vmaddr, uint64_t addr,
1172  uint64_t size) {
1174  if (verbose) {
1175  printf("[%s, %s] AddVMRangeForVMAddr(%" PRIx64 ", [%" PRIx64 ", %" PRIx64
1176  "])\n",
1177  GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr, addr,
1178  size);
1179  }
1180  assert(translator_);
1181  for (auto& pair : outputs_) {
1183  if (pair.first->vm_map.TryGetLabel(label_from_vmaddr, &label)) {
1184  bool ok = pair.first->vm_map.AddRangeWithTranslation(
1186  &pair.first->file_map);
1187  if (!ok && verbose_level > 1) {
1188  WARN("VM range ($0, $1) for label $2 extends beyond base map", addr,
1189  size, label);
1190  }
1191  } else if (verbose_level > 1) {
1192  printf("No label found for vmaddr %" PRIx64 "\n", label_from_vmaddr);
1193  }
1194  }
1195 }
1196 
1197 void RangeSink::AddVMRange(const char* analyzer, uint64_t vmaddr,
1198  uint64_t vmsize, const std::string& name) {
1199  bool verbose = IsVerboseForVMRange(vmaddr, vmsize);
1200  if (verbose) {
1201  printf("[%s, %s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
1202  GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
1203  name.data(), vmaddr, vmsize);
1204  }
1205  assert(translator_);
1206  for (auto& pair : outputs_) {
1207  const std::string label = pair.second->Munge(name);
1208  bool ok = pair.first->vm_map.AddRangeWithTranslation(
1209  vmaddr, vmsize, label, translator_->vm_map, verbose,
1210  &pair.first->file_map);
1211  if (!ok) {
1212  WARN("VM range ($0, $1) for label $2 extends beyond base map", vmaddr,
1213  vmsize, name);
1214  }
1215  }
1216 }
1217 
1218 void RangeSink::AddVMRangeAllowAlias(const char* analyzer, uint64_t vmaddr,
1219  uint64_t size, const std::string& name) {
1220  // TODO: maybe track alias (but what would we use it for?)
1221  // TODO: verify that it is in fact an alias.
1222  AddVMRange(analyzer, vmaddr, size, name);
1223 }
1224 
1225 void RangeSink::AddVMRangeIgnoreDuplicate(const char* analyzer, uint64_t vmaddr,
1226  uint64_t vmsize,
1227  const std::string& name) {
1228  // TODO suppress warning that AddVMRange alone might trigger.
1229  AddVMRange(analyzer, vmaddr, vmsize, name);
1230 }
1231 
1232 void RangeSink::AddRange(const char* analyzer, string_view name,
1233  uint64_t vmaddr, uint64_t vmsize, uint64_t fileoff,
1234  uint64_t filesize) {
1235  if (vmsize == RangeMap::kUnknownSize || filesize == RangeMap::kUnknownSize) {
1236  // AddRange() is used for segments and sections; the mappings that establish
1237  // the file <-> vm mapping. The size should always be known. Moreover it
1238  // would be unclear how the logic should work if the size was *not* known.
1239  THROW("AddRange() does not allow unknown size.");
1240  }
1241 
1242  if (IsVerboseForVMRange(vmaddr, vmsize) ||
1243  IsVerboseForFileRange(fileoff, filesize)) {
1244  printf("[%s, %s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
1245  ", %" PRIx64 ")\n",
1246  GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
1247  name.data(), vmaddr, vmsize, fileoff, filesize);
1248  }
1249 
1250  if (translator_) {
1251  if (!translator_->vm_map.CoversRange(vmaddr, vmsize) ||
1252  !translator_->file_map.CoversRange(fileoff, filesize)) {
1253  THROW("Tried to add range that is not covered by base map.");
1254  }
1255  }
1256 
1257  for (auto& pair : outputs_) {
1258  const std::string label = pair.second->Munge(name);
1259  uint64_t common = std::min(vmsize, filesize);
1260 
1261  pair.first->vm_map.AddDualRange(vmaddr, common, fileoff, label);
1262  pair.first->file_map.AddDualRange(fileoff, common, vmaddr, label);
1263 
1264  pair.first->vm_map.AddRange(vmaddr + common, vmsize - common, label);
1265  pair.first->file_map.AddRange(fileoff + common, filesize - common, label);
1266  }
1267 }
1268 
1270  assert(translator_);
1271  uint64_t offset = ptr - file_->data().data();
1272  uint64_t translated;
1273  if (!FileContainsPointer(ptr) ||
1274  !translator_->file_map.Translate(offset, &translated)) {
1275  THROWF("Can't translate file offset ($0) to VM, contains: $1, map:\n$2",
1277  translator_->file_map.DebugString().c_str());
1278  }
1279  return translated;
1280 }
1281 
1283  assert(translator_);
1284  uint64_t translated;
1285  if (!translator_->vm_map.Translate(address, &translated) ||
1286  translated > file_->data().size()) {
1287  THROW("Can't translate VM pointer to file");
1288  }
1289  return file_->data().substr(translated);
1290 }
1291 
1293  uint64_t uncompressed_size) {
1294  if (!arena_) {
1295  THROW("This range sink isn't prepared to zlib decompress.");
1296  }
1297  uint64_t mb = 1 << 20;
1298  // Limit for uncompressed size is 30x the compressed size + 128MB.
1299  if (uncompressed_size > static_cast<uint64_t>(data.size()) * 30 + (128 * mb)) {
1300  fprintf(stderr,
1301  "warning: ignoring compressed debug data, implausible uncompressed "
1302  "size (compressed: %zu, uncompressed: %" PRIu64 ")\n",
1303  data.size(), uncompressed_size);
1304  return absl::string_view();
1305  }
1306  unsigned char *dbuf =
1307  arena_->google::protobuf::Arena::CreateArray<unsigned char>(
1308  arena_, uncompressed_size);
1309  uLongf zliblen = uncompressed_size;
1310  if (uncompress(dbuf, &zliblen, (unsigned char*)(data.data()), data.size()) != Z_OK) {
1311  THROW("Error decompressing debug info");
1312  }
1313  string_view sv(reinterpret_cast<char *>(dbuf), zliblen);
1314  return sv;
1315 }
1316 
1317 // ThreadSafeIterIndex /////////////////////////////////////////////////////////
1318 
1320  public:
1322 
1323  bool TryGetNext(int* index) {
1324  int ret = index_.fetch_add(1, std::memory_order_relaxed);
1325  if (ret >= max_) {
1326  return false;
1327  } else {
1328  *index = ret;
1329  return true;
1330  }
1331  }
1332 
1334  std::lock_guard<std::mutex> lock(mutex_);
1335  index_ = max_;
1337  }
1338 
1340  std::lock_guard<std::mutex> lock(mutex_);
1341  if (error_.empty()) {
1342  return false;
1343  } else {
1344  *error = error_;
1345  return true;
1346  }
1347  }
1348 
1349  private:
1350  std::atomic<int> index_;
1353  const int max_;
1354 };
1355 
1356 
1357 // Bloaty //////////////////////////////////////////////////////////////////////
1358 
1359 // Represents a program execution and associated state.
1360 
1363  : definition(definition_),
1364  effective_source(definition_.number),
1365  munger(new NameMunger()) {}
1366 
1368  // This will differ from definition.number for kSymbols, where we use the
1369  // --demangle flag to set the true/effective source.
1371  std::unique_ptr<NameMunger> munger;
1372 };
1373 
1374 class Bloaty {
1375  public:
1376  Bloaty(const InputFileFactory& factory, const Options& options);
1377  Bloaty(const Bloaty&) = delete;
1378  Bloaty& operator=(const Bloaty&) = delete;
1379 
1380  void AddFilename(const std::string& filename, bool base_file);
1381  void AddDebugFilename(const std::string& filename);
1382 
1383  size_t GetSourceCount() const { return sources_.size(); }
1384 
1385  void DefineCustomDataSource(const CustomDataSource& source);
1386 
1387  void AddDataSource(const std::string& name);
1388  void ScanAndRollup(const Options& options, RollupOutput* output);
1389  void DisassembleFunction(string_view function, const Options& options,
1390  RollupOutput* output);
1391 
1392  private:
1393  template <size_t T>
1395  const Options& options) {
1396  for (size_t i = 0; i < T; i++) {
1397  const DataSourceDefinition& source = sources[i];
1398  auto configured_source = absl::make_unique<ConfiguredDataSource>(source);
1399 
1400  if (configured_source->effective_source == DataSource::kSymbols) {
1401  configured_source->effective_source = EffectiveSymbolSource(options);
1402  }
1403 
1404  all_known_sources_[source.name] = std::move(configured_source);
1405  }
1406  }
1407 
1408  static DataSource EffectiveSymbolSource(const Options& options) {
1409  switch (options.demangle()) {
1410  case Options::DEMANGLE_NONE:
1411  return DataSource::kRawSymbols;
1412  case Options::DEMANGLE_SHORT:
1414  case Options::DEMANGLE_FULL:
1415  return DataSource::kFullSymbols;
1416  default:
1418  }
1419  }
1420 
1421  void ScanAndRollupFiles(const std::vector<std::string>& filenames,
1422  std::vector<std::string>* build_ids,
1423  Rollup* rollup) const;
1424  void ScanAndRollupFile(const std::string& filename, Rollup* rollup,
1425  std::vector<std::string>* out_build_ids) const;
1426 
1427  std::unique_ptr<ObjectFile> GetObjectFile(const std::string& filename) const;
1428 
1430  const Options options_;
1431 
1432  // All data sources, indexed by name.
1433  // Contains both built-in sources and custom sources.
1434  std::map<std::string, std::unique_ptr<ConfiguredDataSource>>
1436 
1437  // Sources the user has actually selected, in the order selected.
1438  // Points to entries in all_known_sources_.
1439  std::vector<ConfiguredDataSource*> sources_;
1440  std::vector<std::string> source_names_;
1441 
1442  struct InputFileInfo {
1445  };
1446  std::vector<InputFileInfo> input_files_;
1447  std::vector<InputFileInfo> base_files_;
1448  std::map<std::string, std::string> debug_files_;
1449 
1450  // For allocating memory, like to decompress compressed sections.
1451  std::unique_ptr<google::protobuf::Arena> arena_;
1452 };
1453 
1454 Bloaty::Bloaty(const InputFileFactory &factory, const Options &options)
1455  : file_factory_(factory), options_(options),
1458 }
1459 
1460 std::unique_ptr<ObjectFile> Bloaty::GetObjectFile(
1461  const std::string& filename) const {
1462  std::unique_ptr<InputFile> file(file_factory_.OpenFile(filename));
1463  auto object_file = TryOpenELFFile(file);
1464 
1465  if (!object_file.get()) {
1466  object_file = TryOpenMachOFile(file);
1467  }
1468 
1469  if (!object_file.get()) {
1470  object_file = TryOpenWebAssemblyFile(file);
1471  }
1472 
1473  if (!object_file.get()) {
1474  object_file = TryOpenPEFile(file);
1475  }
1476 
1477  if (!object_file.get()) {
1478  THROWF("unknown file type for file '$0'", filename.c_str());
1479  }
1480 
1481  return object_file;
1482 }
1483 
1484 void Bloaty::AddFilename(const std::string& filename, bool is_base) {
1485  auto object_file = GetObjectFile(filename);
1486  std::string build_id = object_file->GetBuildId();
1487 
1488  if (is_base) {
1489  base_files_.push_back({filename, build_id});
1490  } else {
1491  input_files_.push_back({filename, build_id});
1492  }
1493 }
1494 
1496  auto object_file = GetObjectFile(filename);
1497  std::string build_id = object_file->GetBuildId();
1498  if (build_id.size() == 0) {
1499  THROWF("File '$0' has no build ID, cannot be used as a debug file",
1500  filename);
1501  }
1502  debug_files_[build_id] = filename;
1503 }
1504 
1505 void Bloaty::DefineCustomDataSource(const CustomDataSource& source) {
1506  if (source.base_data_source() == "symbols") {
1507  THROW(
1508  "For custom data sources, use one of {rawsymbols, shortsymbols, "
1509  "fullsymbols} for base_data_source instead of 'symbols', so you aren't "
1510  "sensitive to the --demangle parameter.");
1511  }
1512 
1513  auto iter = all_known_sources_.find(source.base_data_source());
1514 
1515  if (iter == all_known_sources_.end()) {
1516  THROWF("custom data source '$0': no such base source '$1'.\nTry --list-sources to see valid sources.", source.name(),
1517  source.base_data_source());
1518  } else if (!iter->second->munger->IsEmpty()) {
1519  THROWF("custom data source '$0' tries to depend on custom data source '$1'",
1520  source.name(), source.base_data_source());
1521  }
1522 
1523  all_known_sources_[source.name()] =
1524  absl::make_unique<ConfiguredDataSource>(iter->second->definition);
1525  NameMunger* munger = all_known_sources_[source.name()]->munger.get();
1526  for (const auto& regex : source.rewrite()) {
1527  munger->AddRegex(regex.pattern(), regex.replacement());
1528  }
1529 }
1530 
1532  source_names_.emplace_back(name);
1533  auto it = all_known_sources_.find(name);
1534  if (it == all_known_sources_.end()) {
1535  THROWF("no such data source: $0.\nTry --list-sources to see valid sources.", name);
1536  }
1537 
1538  sources_.emplace_back(it->second.get());
1539 }
1540 
1541 // All of the DualMaps for a given file.
1542 struct DualMaps {
1543  public:
1545  // Base map.
1546  AppendMap();
1547  }
1548 
1550  maps_.emplace_back(new DualMap);
1551  return maps_.back().get();
1552  }
1553 
1554  void ComputeRollup(Rollup* rollup) {
1555  for (auto& map : maps_) {
1556  map->vm_map.Compress();
1557  map->file_map.Compress();
1558  }
1559  RangeMap::ComputeRollup(VmMaps(), [=](const std::vector<std::string>& keys,
1561  return rollup->AddSizes(keys, end - addr, true);
1562  });
1564  FileMaps(),
1565  [=](const std::vector<std::string>& keys, uint64_t addr, uint64_t end) {
1566  return rollup->AddSizes(keys, end - addr, false);
1567  });
1568  }
1569 
1570  void PrintMaps(const std::vector<const RangeMap*> maps) {
1571  uint64_t last = 0;
1572  uint64_t max = maps[0]->GetMaxAddress();
1573  int hex_digits = max > 0 ? std::ceil(std::log2(max) / 4) : 0;
1574  RangeMap::ComputeRollup(maps, [&](const std::vector<std::string>& keys,
1576  if (addr > last) {
1577  PrintMapRow("[-- Nothing mapped --]", last, addr, hex_digits);
1578  }
1579  PrintMapRow(KeysToString(keys), addr, end, hex_digits);
1580  last = end;
1581  });
1582  printf("\n");
1583  }
1584 
1587 
1588  std::string KeysToString(const std::vector<std::string>& keys) {
1589  std::string ret;
1590 
1591  // Start at offset 1 to skip the base map.
1592  for (size_t i = 1; i < keys.size(); i++) {
1593  if (i > 1) {
1594  ret += "\t";
1595  }
1596  ret += keys[i];
1597  }
1598 
1599  return ret;
1600  }
1601 
1603  printf("%.*" PRIx64 "-%.*" PRIx64 "\t %s\t\t%.*s\n", hex_digits, start,
1604  hex_digits, end, LeftPad(std::to_string(end - start), 10).c_str(),
1605  (int)str.size(), str.data());
1606  }
1607 
1608  DualMap* base_map() { return maps_[0].get(); }
1609 
1610  private:
1611  std::vector<const RangeMap*> VmMaps() const {
1612  std::vector<const RangeMap*> ret;
1613  for (const auto& map : maps_) {
1614  ret.push_back(&map->vm_map);
1615  }
1616  return ret;
1617  }
1618 
1619  std::vector<const RangeMap*> FileMaps() const {
1620  std::vector<const RangeMap*> ret;
1621  for (const auto& map : maps_) {
1622  ret.push_back(&map->file_map);
1623  }
1624  return ret;
1625  }
1626 
1627  std::vector<std::unique_ptr<DualMap>> maps_;
1628 };
1629 
1631  std::vector<std::string>* out_build_ids) const {
1632  auto file = GetObjectFile(filename);
1633 
1634  DualMaps maps;
1635  std::vector<std::unique_ptr<RangeSink>> sinks;
1636  std::vector<RangeSink*> sink_ptrs;
1637  std::vector<RangeSink*> filename_sink_ptrs;
1638 
1639  // Base map always goes first.
1640  sinks.push_back(absl::make_unique<RangeSink>(
1641  &file->file_data(), options_, DataSource::kSegments, nullptr, nullptr));
1642  NameMunger empty_munger;
1643  sinks.back()->AddOutput(maps.base_map(), &empty_munger);
1644  sink_ptrs.push_back(sinks.back().get());
1645 
1646  for (auto source : sources_) {
1647  sinks.push_back(absl::make_unique<RangeSink>(&file->file_data(), options_,
1648  source->effective_source,
1649  maps.base_map(), arena_.get()));
1650  sinks.back()->AddOutput(maps.AppendMap(), source->munger.get());
1651  // We handle the kInputFiles data source internally, without handing it off
1652  // to the file format implementation. This seems slightly simpler, since
1653  // the file format has to deal with armembers too.
1654  if (source->effective_source == DataSource::kInputFiles) {
1655  filename_sink_ptrs.push_back(sinks.back().get());
1656  } else {
1657  sink_ptrs.push_back(sinks.back().get());
1658  }
1659  }
1660 
1661  std::unique_ptr<ObjectFile> debug_file;
1662  std::string build_id = file->GetBuildId();
1663  if (!build_id.empty()) {
1664  auto iter = debug_files_.find(build_id);
1665  if (iter != debug_files_.end()) {
1666  debug_file = GetObjectFile(iter->second);
1667  file->set_debug_file(debug_file.get());
1668  out_build_ids->push_back(build_id);
1669  }
1670  }
1671 
1672  int64_t filesize_before = rollup->file_total() +
1673  rollup->filtered_file_total();
1674  file->ProcessFile(sink_ptrs);
1675 
1676  // kInputFile source: Copy the base map to the filename sink(s).
1677  for (auto sink : filename_sink_ptrs) {
1678  maps.base_map()->vm_map.ForEachRange(
1680  sink->AddVMRange("inputfile_vmcopier", start, length,
1681  sink->input_file().filename());
1682  });
1683  maps.base_map()->file_map.ForEachRange(
1685  sink->AddFileRange("inputfile_filecopier",
1686  sink->input_file().filename(), start, length);
1687  });
1688  }
1689 
1690  maps.ComputeRollup(rollup);
1691 
1692  // The ObjectFile implementation must guarantee this.
1693  int64_t filesize = rollup->file_total() +
1694  rollup->filtered_file_total() - filesize_before;
1695  (void)filesize;
1696  assert(filesize == file->file_data().data().size());
1697 
1698  if (verbose_level > 0 || options_.dump_raw_map()) {
1699  printf("Maps for %s:\n\n", filename.c_str());
1700  if (show != ShowDomain::kShowVM) {
1701  printf("FILE MAP:\n");
1702  maps.PrintFileMaps();
1703  }
1704  if (show != ShowDomain::kShowFile) {
1705  printf("VM MAP:\n");
1706  maps.PrintVMMaps();
1707  }
1708  }
1709 }
1710 
1712  const std::vector<std::string>& filenames,
1713  std::vector<std::string>* build_ids,
1714  Rollup * rollup) const {
1715  int num_cpus = std::thread::hardware_concurrency();
1716  int num_threads = std::min(num_cpus, static_cast<int>(filenames.size()));
1717 
1718  struct PerThreadData {
1719  Rollup rollup;
1720  std::vector<std::string> build_ids;
1721  };
1722 
1723  std::vector<PerThreadData> thread_data(num_threads);
1724  std::vector<std::thread> threads(num_threads);
1725  ThreadSafeIterIndex index(filenames.size());
1726 
1727  std::unique_ptr<ReImpl> regex = nullptr;
1728  if (options_.has_source_filter()) {
1729  regex = absl::make_unique<ReImpl>(options_.source_filter());
1730  }
1731 
1732  for (int i = 0; i < num_threads; i++) {
1733  thread_data[i].rollup.SetFilterRegex(regex.get());
1734 
1735  threads[i] = std::thread([this, &index, &filenames](PerThreadData* data) {
1736  try {
1737  int j;
1738  while (index.TryGetNext(&j)) {
1739  ScanAndRollupFile(filenames[j], &data->rollup, &data->build_ids);
1740  }
1741  } catch (const bloaty::Error& e) {
1742  index.Abort(e.what());
1743  }
1744  }, &thread_data[i]);
1745  }
1746 
1747  for (int i = 0; i < num_threads; i++) {
1748  threads[i].join();
1749  PerThreadData* data = &thread_data[i];
1750  if (i == 0) {
1751  *rollup = std::move(data->rollup);
1752  } else {
1753  rollup->Add(data->rollup);
1754  }
1755 
1756  build_ids->insert(build_ids->end(),
1757  data->build_ids.begin(),
1758  data->build_ids.end());
1759  }
1760 
1762  if (index.TryGetError(&error)) {
1763  THROW(error.c_str());
1764  }
1765 }
1766 
1768  if (input_files_.empty()) {
1769  THROW("no filename specified");
1770  }
1771 
1772  for (const auto& name : source_names_) {
1773  output->AddDataSourceName(name);
1774  }
1775 
1776  Rollup rollup;
1777  std::vector<std::string> build_ids;
1778  std::vector<std::string> input_filenames;
1779  for (const auto& file_info : input_files_) {
1780  input_filenames.push_back(file_info.filename_);
1781  }
1782  ScanAndRollupFiles(input_filenames, &build_ids, &rollup);
1783 
1784  if (!base_files_.empty()) {
1785  Rollup base;
1786  std::vector<std::string> base_filenames;
1787  for (const auto& file_info : base_files_) {
1788  base_filenames.push_back(file_info.filename_);
1789  }
1790  ScanAndRollupFiles(base_filenames, &build_ids, &base);
1791  rollup.Subtract(base);
1793  } else {
1795  }
1796 
1797  for (const auto& build_id : build_ids) {
1798  debug_files_.erase(build_id);
1799  }
1800 
1801  // Error out if some --debug-files were not used.
1802  if (!debug_files_.empty()) {
1803  std::string input_files;
1804  std::string unused_debug;
1805  for (const auto& pair : debug_files_) {
1806  unused_debug += absl::Substitute(
1807  "$0 $1\n",
1808  absl::BytesToHexString(pair.first).c_str(),
1809  pair.second.c_str());
1810  }
1811 
1812  for (const auto& file_info : input_files_) {
1813  input_files += absl::Substitute(
1814  "$0 $1\n", absl::BytesToHexString(file_info.build_id_).c_str(),
1815  file_info.filename_.c_str());
1816  }
1817  for (const auto& file_info : base_files_) {
1818  input_files += absl::Substitute(
1819  "$0 $1\n", absl::BytesToHexString(file_info.build_id_).c_str(),
1820  file_info.filename_.c_str());
1821  }
1822  THROWF(
1823  "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
1824  unused_debug.c_str(), input_files.c_str());
1825  }
1826 }
1827 
1828 void Bloaty::DisassembleFunction(string_view function, const Options& options,
1829  RollupOutput* output) {
1830  DisassemblyInfo info;
1831  for (const auto& file_info : input_files_) {
1832  auto file = GetObjectFile(file_info.filename_);
1833  if (file->GetDisassemblyInfo(function, EffectiveSymbolSource(options),
1834  &info)) {
1835  output->SetDisassembly(::bloaty::DisassembleFunction(info));
1836  return;
1837  }
1838  }
1839 
1840  THROWF("Couldn't find function $0 to disassemble", function);
1841 }
1842 
1843 const char usage[] = R"(Bloaty McBloatface: a size profiler for binaries.
1844 
1845 USAGE: bloaty [OPTION]... FILE... [-- BASE_FILE...]
1846 
1847 Options:
1848 
1849  --csv Output in CSV format instead of human-readable.
1850  --tsv Output in TSV format instead of human-readable.
1851  -c FILE Load configuration from <file>.
1852  -d SOURCE,SOURCE Comma-separated list of sources to scan.
1853  --debug-file=FILE Use this file for debug symbols and/or symbol table.
1854  -C MODE How to demangle symbols. Possible values are:
1855  --demangle=MODE --demangle=none no demangling, print raw symbols
1856  --demangle=short demangle, but omit arg/return types
1857  --demangle=full print full demangled type
1858  The default is --demangle=short.
1859  --disassemble=FUNCTION
1860  Disassemble this function (EXPERIMENTAL)
1861  --domain=DOMAIN Which domains to show. Possible values are:
1862  --domain=vm
1863  --domain=file
1864  --domain=both (the default)
1865  -n NUM How many rows to show per level before collapsing
1866  other keys into '[Other]'. Set to '0' for unlimited.
1867  Defaults to 20.
1868  -s SORTBY Whether to sort by VM or File size. Possible values
1869  are:
1870  -s vm
1871  -s file
1872  -s both (the default: sorts by max(vm, file)).
1873  -w Wide output; don't truncate long labels.
1874  --help Display this message and exit.
1875  --list-sources Show a list of available sources and exit.
1876  --source-filter=PATTERN
1877  Only show keys with names matching this pattern.
1878 
1879 Options for debugging Bloaty:
1880 
1881  --debug-vmaddr=ADDR
1882  --debug-fileoff=OFF
1883  Print extended debugging information for the given
1884  VM address and/or file offset.
1885  -v Verbose output. Dumps warnings encountered during
1886  processing and full VM/file maps at the end.
1887  Add more v's (-vv, -vvv) for even more.
1888 )";
1889 
1890 class ArgParser {
1891  public:
1892  ArgParser(int* argc, char** argv[])
1893  : argc_(*argc),
1894  argv_(*argv, *argv + *argc),
1895  out_argc_(argc),
1896  out_argv_(argv) {
1897  *out_argc_ = 0;
1898  ConsumeAndSaveArg(); // Executable name.
1899  }
1900 
1901  bool IsDone() { return index_ == argc_; }
1902 
1904  assert(!IsDone());
1905  return string_view(argv_[index_]);
1906  }
1907 
1909  string_view ret = Arg();
1910  index_++;
1911  return ret;
1912  }
1913 
1915  (*out_argv_)[(*out_argc_)++] = argv_[index_++];
1916  }
1917 
1918  // Singular flag like --csv or -v.
1920  if (Arg() == flag) {
1921  ConsumeArg();
1922  return true;
1923  } else {
1924  return false;
1925  }
1926  }
1927 
1928  // Option taking an argument, for example:
1929  // -n 20
1930  // --config=file.bloaty
1931  //
1932  // For --long-options we accept both:
1933  // --long_option value
1934  // --long_option=value
1936  assert(flag.size() > 1);
1937  bool is_long = flag[1] == '-';
1938  string_view arg = Arg();
1939  if (TryParseFlag(flag)) {
1940  if (IsDone()) {
1941  THROWF("option '$0' requires an argument", flag);
1942  }
1943  *val = ConsumeArg();
1944  return true;
1945  } else if (is_long && absl::ConsumePrefix(&arg, std::string(flag) + "=")) {
1946  *val = arg;
1947  index_++;
1948  return true;
1949  } else {
1950  return false;
1951  }
1952  }
1953 
1955  string_view val_str;
1956  if (!TryParseOption(flag, &val_str)) {
1957  return false;
1958  }
1959 
1960  if (!absl::SimpleAtoi(val_str, val)) {
1961  THROWF("option '$0' had non-integral argument: $1", flag, val_str);
1962  }
1963 
1964  return true;
1965  }
1966 
1968  string_view val_str;
1969  if (!TryParseOption(flag, &val_str)) {
1970  return false;
1971  }
1972 
1973  try {
1974  *val = std::stoull(std::string(val_str), nullptr, 0);
1975  } catch (...) {
1976  THROWF("option '$0' had non-integral argument: $1", flag, val_str);
1977  }
1978 
1979  return true;
1980  }
1981 
1982  public:
1983  int argc_;
1984  std::vector<char*> argv_;
1986  char*** out_argv_;
1987  int index_ = 0;
1988 };
1989 
1990 bool DoParseOptions(bool skip_unknown, int* argc, char** argv[],
1991  Options* options, OutputOptions* output_options) {
1992  bool saw_separator = false;
1993  ArgParser args(argc, argv);
1995  int int_option;
1996  uint64_t uint64_option;
1997  bool has_domain = false;
1998 
1999  while (!args.IsDone()) {
2000  if (args.TryParseFlag("--")) {
2001  if (saw_separator) {
2002  THROW("'--' option should only be specified once");
2003  }
2004  saw_separator = true;
2005  } else if (args.TryParseFlag("--csv")) {
2006  output_options->output_format = OutputFormat::kCSV;
2007  } else if (args.TryParseFlag("--tsv")) {
2008  output_options->output_format = OutputFormat::kTSV;
2009  } else if (args.TryParseFlag("--raw-map")) {
2010  options->set_dump_raw_map(true);
2011  } else if (args.TryParseOption("-c", &option)) {
2012  std::ifstream input_file(std::string(option), std::ios::in);
2013  if (!input_file.is_open()) {
2014  THROWF("couldn't open file $0", option);
2015  }
2018  THROWF("error parsing configuration out of file $0", option);
2019  }
2020  } else if (args.TryParseOption("-d", &option)) {
2021  std::vector<std::string> names = absl::StrSplit(option, ',');
2022  for (const auto& name : names) {
2023  options->add_data_source(name);
2024  }
2025  } else if (args.TryParseOption("-C", &option) ||
2026  args.TryParseOption("--demangle", &option)) {
2027  if (option == "none") {
2028  options->set_demangle(Options::DEMANGLE_NONE);
2029  } else if (option == "short") {
2030  options->set_demangle(Options::DEMANGLE_SHORT);
2031  } else if (option == "full") {
2032  options->set_demangle(Options::DEMANGLE_FULL);
2033  } else {
2034  THROWF("unknown value for --demangle: $0", option);
2035  }
2036  } else if (args.TryParseOption("--debug-file", &option)) {
2037  options->add_debug_filename(std::string(option));
2038  } else if (args.TryParseUint64Option("--debug-fileoff", &uint64_option)) {
2039  if (options->has_debug_fileoff()) {
2040  THROW("currently we only support a single debug fileoff");
2041  }
2042  options->set_debug_fileoff(uint64_option);
2043  } else if (args.TryParseUint64Option("--debug-vmaddr", &uint64_option)) {
2044  if (options->has_debug_vmaddr()) {
2045  THROW("currently we only support a single debug vmaddr");
2046  }
2047  options->set_debug_vmaddr(uint64_option);
2048  } else if (args.TryParseOption("--disassemble", &option)) {
2049  options->mutable_disassemble_function()->assign(std::string(option));
2050  } else if (args.TryParseIntegerOption("-n", &int_option)) {
2051  if (int_option == 0) {
2052  options->set_max_rows_per_level(INT64_MAX);
2053  } else {
2054  options->set_max_rows_per_level(int_option);
2055  }
2056  } else if (args.TryParseOption("--domain", &option)) {
2057  has_domain = true;
2058  if (option == "vm") {
2059  show = output_options->show = ShowDomain::kShowVM;
2060  } else if (option == "file") {
2061  show = output_options->show = ShowDomain::kShowFile;
2062  } else if (option == "both") {
2063  show = output_options->show = ShowDomain::kShowBoth;
2064  } else {
2065  THROWF("unknown value for --domain: $0", option);
2066  }
2067  } else if (args.TryParseOption("-s", &option)) {
2068  if (option == "vm") {
2069  options->set_sort_by(Options::SORTBY_VMSIZE);
2070  } else if (option == "file") {
2071  options->set_sort_by(Options::SORTBY_FILESIZE);
2072  } else if (option == "both") {
2073  options->set_sort_by(Options::SORTBY_BOTH);
2074  } else {
2075  THROWF("unknown value for -s: $0", option);
2076  }
2077  } else if (args.TryParseOption("--source-filter", &option)) {
2078  options->set_source_filter(std::string(option));
2079  } else if (args.TryParseFlag("-v")) {
2080  options->set_verbose_level(1);
2081  } else if (args.TryParseFlag("-vv")) {
2082  options->set_verbose_level(2);
2083  } else if (args.TryParseFlag("-vvv")) {
2084  options->set_verbose_level(3);
2085  } else if (args.TryParseFlag("-w")) {
2086  output_options->max_label_len = SIZE_MAX;
2087  } else if (args.TryParseFlag("--list-sources")) {
2088  for (const auto& source : data_sources) {
2089  fprintf(stderr, "%s %s\n", FixedWidthString(source.name, 15).c_str(),
2090  source.description);
2091  }
2092  return false;
2093  } else if (args.TryParseFlag("--help")) {
2094  puts(usage);
2095  return false;
2096  } else if (args.TryParseFlag("--version")) {
2097  printf("Bloaty McBloatface 1.1\n");
2098  exit(0);
2099  } else if (absl::StartsWith(args.Arg(), "-")) {
2100  if (skip_unknown) {
2101  args.ConsumeAndSaveArg();
2102  } else {
2103  THROWF("Unknown option: $0", args.Arg());
2104  }
2105  } else {
2106  if (saw_separator) {
2107  options->add_base_filename(std::string(args.ConsumeArg()));
2108  } else {
2109  options->add_filename(std::string(args.ConsumeArg()));
2110  }
2111  }
2112  }
2113 
2114  if (options->data_source_size() == 0 &&
2115  !options->has_disassemble_function()) {
2116  // Default when no sources are specified.
2117  options->add_data_source("sections");
2118  }
2119 
2120  if (has_domain && !options->has_sort_by()) {
2121  // Default to sorting by what we are showing.
2122  switch (output_options->show) {
2123  case ShowDomain::kShowFile:
2124  options->set_sort_by(Options::SORTBY_FILESIZE);
2125  break;
2126  case ShowDomain::kShowVM:
2127  options->set_sort_by(Options::SORTBY_VMSIZE);
2128  break;
2129  case ShowDomain::kShowBoth:
2130  options->set_sort_by(Options::SORTBY_BOTH);
2131  break;
2132  }
2133  }
2134 
2135  return true;
2136 }
2137 
2138 bool ParseOptions(bool skip_unknown, int* argc, char** argv[], Options* options,
2139  OutputOptions* output_options, std::string* error) {
2140  try {
2141  return DoParseOptions(skip_unknown, argc, argv, options, output_options);
2142  } catch (const bloaty::Error& e) {
2143  error->assign(e.what());
2144  return false;
2145  }
2146 }
2147 
2148 void BloatyDoMain(const Options& options, const InputFileFactory& file_factory,
2149  RollupOutput* output) {
2150  bloaty::Bloaty bloaty(file_factory, options);
2151 
2152  if (options.filename_size() == 0) {
2153  THROW("must specify at least one file");
2154  }
2155 
2156  if (options.max_rows_per_level() < 1) {
2157  THROW("max_rows_per_level must be at least 1");
2158  }
2159 
2160  for (auto& filename : options.filename()) {
2161  bloaty.AddFilename(filename, false);
2162  }
2163 
2164  for (auto& base_filename : options.base_filename()) {
2165  bloaty.AddFilename(base_filename, true);
2166  }
2167 
2168  for (auto& debug_filename : options.debug_filename()) {
2169  bloaty.AddDebugFilename(debug_filename);
2170  }
2171 
2172  for (const auto& custom_data_source : options.custom_data_source()) {
2173  bloaty.DefineCustomDataSource(custom_data_source);
2174  }
2175 
2176  for (const auto& data_source : options.data_source()) {
2177  bloaty.AddDataSource(data_source);
2178  }
2179 
2180  if (options.has_source_filter()) {
2181  ReImpl re(options.source_filter());
2182  if (!re.ok()) {
2183  THROW("invalid regex for source_filter");
2184  }
2185  }
2186 
2187  verbose_level = options.verbose_level();
2188 
2189  if (options.data_source_size() > 0) {
2190  bloaty.ScanAndRollup(options, output);
2191  } else if (options.has_disassemble_function()) {
2192  bloaty.DisassembleFunction(options.disassemble_function(), options, output);
2193  }
2194 }
2195 
2196 bool BloatyMain(const Options& options, const InputFileFactory& file_factory,
2198  try {
2199  BloatyDoMain(options, file_factory, output);
2200  return true;
2201  } catch (const bloaty::Error& e) {
2202  error->assign(e.what());
2203  return false;
2204  }
2205 }
2206 
2207 } // namespace bloaty
absl::StrSplit
strings_internal::Splitter< typename strings_internal::SelectDelimiter< Delimiter >::type, AllowEmpty, absl::string_view > StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d)
Definition: abseil-cpp/absl/strings/str_split.h:499
bloaty::ArgParser::TryParseFlag
bool TryParseFlag(string_view flag)
Definition: bloaty.cc:1919
bloaty::Bloaty::input_files_
std::vector< InputFileInfo > input_files_
Definition: bloaty.cc:1446
xds_interop_client.str
str
Definition: xds_interop_client.py:487
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
bloaty::RangeSink::AddFileRangeForFileRange
void AddFileRangeForFileRange(const char *analyzer, absl::string_view from_file_range, absl::string_view file_range)
Definition: bloaty.cc:1139
bloaty::GetDataSourceLabel
const char * GetDataSourceLabel(DataSource source)
Definition: bloaty.cc:103
bloaty::RangeSink::AddFileRange
void AddFileRange(const char *analyzer, absl::string_view name, uint64_t fileoff, uint64_t filesize)
Definition: bloaty.cc:1088
bloaty::Bloaty::ScanAndRollupFile
void ScanAndRollupFile(const std::string &filename, Rollup *rollup, std::vector< std::string > *out_build_ids) const
Definition: bloaty.cc:1630
flag
uint32_t flag
Definition: ssl_versions.cc:162
uLongf
uLong FAR uLongf
Definition: bloaty/third_party/zlib/zconf.h:405
bloaty::RollupRow::filepercent
double filepercent
Definition: bloaty.h:345
bloaty::ArgParser::TryParseOption
bool TryParseOption(string_view flag, string_view *val)
Definition: bloaty.cc:1935
bloaty::RangeSink::arena_
google::protobuf::Arena * arena_
Definition: bloaty.h:229
bloaty::NameMunger::regexes_
std::vector< std::pair< std::unique_ptr< ReImpl >, std::string > > regexes_
Definition: bloaty.h:250
filename
const char * filename
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
bloaty
Definition: bloaty.cc:69
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
bloaty::Rollup::CreateRows
void CreateRows(RollupRow *row, const Rollup *base, const Options &options, bool is_toplevel) const
Definition: bloaty.cc:406
Arena
struct Arena Arena
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/arena.h:189
ARRAY_SIZE
#define ARRAY_SIZE(array)
Definition: bloaty.cc:101
regen-readme.it
it
Definition: regen-readme.py:15
bloaty::Rollup::children_
ChildMap children_
Definition: bloaty.cc:333
bloaty::ConfiguredDataSource::ConfiguredDataSource
ConfiguredDataSource(const DataSourceDefinition &definition_)
Definition: bloaty.cc:1362
bloaty::RollupOutput::diff_mode_
bool diff_mode_
Definition: bloaty.h:406
uncompress
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: bloaty/third_party/zlib/uncompr.c:86
bloaty::RangeSink::translator_
const DualMap * translator_
Definition: bloaty.h:227
bloaty::RollupOutput::source_names_
std::vector< std::string > source_names_
Definition: bloaty.h:401
bloaty::InputFileFactory::OpenFile
virtual std::unique_ptr< InputFile > OpenFile(const std::string &filename) const =0
bloaty::ArgParser::argc_
int argc_
Definition: bloaty.cc:1983
bloaty::DualMaps::ComputeRollup
void ComputeRollup(Rollup *rollup)
Definition: bloaty.cc:1554
bloaty::debug_fileoff
uint64_t debug_fileoff
Definition: bloaty.cc:1008
file
const grpc_generator::File * file
Definition: python_private_generator.h:38
bloaty::Bloaty::ScanAndRollup
void ScanAndRollup(const Options &options, RollupOutput *output)
Definition: bloaty.cc:1767
bloaty::BloatyDoMain
void BloatyDoMain(const Options &options, const InputFileFactory &file_factory, RollupOutput *output)
Definition: bloaty.cc:2148
bloaty::NameMunger::Munge
std::string Munge(absl::string_view name) const
Definition: bloaty.cc:213
bloaty::Rollup::ChildMap
std::unordered_map< std::string, std::unique_ptr< Rollup > > ChildMap
Definition: bloaty.cc:332
bloaty::Bloaty::GetSourceCount
size_t GetSourceCount() const
Definition: bloaty.cc:1383
bloaty::OutputFormat::kTSV
@ kTSV
bloaty::others_label
std::string others_label
Definition: bloaty.cc:251
tests.google.protobuf.internal.message_test.isnan
def isnan(val)
Definition: bloaty/third_party/protobuf/python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/message_test.py:65
bloaty::FileDescriptor::fd
int fd()
Definition: bloaty.cc:882
keys
const void * keys
Definition: abseil-cpp/absl/random/internal/randen.cc:49
mutex
static uv_mutex_t mutex
Definition: threadpool.c:34
bloaty::MmapInputFile
Definition: bloaty.cc:863
bloaty::MmapInputFile::MmapInputFile
MmapInputFile(const std::string &filename)
Definition: bloaty.cc:888
bloaty::RollupOutput::PrettyPrint
void PrettyPrint(const OutputOptions &options, std::ostream *out) const
Definition: bloaty.cc:755
bloaty::Rollup::filtered_file_total
int64_t filtered_file_total() const
Definition: bloaty.cc:320
bloaty::DataSource::kShortSymbols
@ kShortSymbols
INT64_MAX
#define INT64_MAX
Definition: stdint-msvc2008.h:139
file_
FileDescriptorProto * file_
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/annotation_test_util.cc:68
bloaty::verbose_level
int verbose_level
Definition: bloaty.cc:74
bloaty::DualMap::vm_map
RangeMap vm_map
Definition: bloaty.h:313
bloaty::RangeMap::kUnknownSize
static constexpr uint64_t kUnknownSize
Definition: range_map.h:154
options
double_dict options[]
Definition: capstone_test.c:55
bloaty::Bloaty::file_factory_
const InputFileFactory & file_factory_
Definition: bloaty.cc:1429
absl::StartsWith
bool StartsWith(absl::string_view text, absl::string_view prefix) noexcept
Definition: third_party/abseil-cpp/absl/strings/match.h:58
bloaty::Rollup::SortAndAggregateRows
void SortAndAggregateRows(RollupRow *row, const Rollup *base, const Options &options, bool is_toplevel) const
Definition: bloaty.cc:429
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
bloaty::Bloaty::operator=
Bloaty & operator=(const Bloaty &)=delete
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
names
sub_type names
Definition: cxa_demangle.cpp:4905
bloaty::Rollup::CreateDiffModeRollupOutput
void CreateDiffModeRollupOutput(Rollup *base, const Options &options, RollupOutput *output) const
Definition: bloaty.cc:274
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
Arena
Definition: arena.c:39
bloaty::DualMaps::FileMaps
std::vector< const RangeMap * > FileMaps() const
Definition: bloaty.cc:1619
bloaty.h
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
UINT64_MAX
#define UINT64_MAX
Definition: stdint-msvc2008.h:143
bloaty::DisassembleFunction
std::string DisassembleFunction(const DisassemblyInfo &info)
Definition: disassemble.cc:135
bloaty::BloatyMain
bool BloatyMain(const Options &options, const InputFileFactory &file_factory, RollupOutput *output, std::string *error)
Definition: bloaty.cc:2196
z_size_t
size_t z_size_t
Definition: bloaty.cc:20
bloaty::DataSource::kArchiveMembers
@ kArchiveMembers
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
bloaty::RangeMap::CoversRange
bool CoversRange(uint64_t addr, uint64_t size) const
Definition: range_map.cc:307
bloaty::RollupOutput
Definition: bloaty.h:376
bloaty::RangeMap::AddRangeWithTranslation
bool AddRangeWithTranslation(uint64_t addr, uint64_t size, const std::string &val, const RangeMap &translator, bool verbose, RangeMap *other)
Definition: range_map.cc:253
status
absl::Status status
Definition: rls.cc:251
bloaty::SignOf
int SignOf(long val)
Definition: bloaty.cc:114
bloaty::DataSourceDefinition
Definition: bloaty.cc:77
setup.name
name
Definition: setup.py:542
bloaty::Error
Definition: bloaty/src/util.h:26
bloaty::Bloaty::DefineCustomDataSource
void DefineCustomDataSource(const CustomDataSource &source)
Definition: bloaty.cc:1505
bloaty::RangeSink::AddVMRange
void AddVMRange(const char *analyzer, uint64_t vmaddr, uint64_t vmsize, const std::string &name)
Definition: bloaty.cc:1197
bloaty::RangeSink::IsVerboseForFileRange
bool IsVerboseForFileRange(uint64_t fileoff, uint64_t filesize)
Definition: bloaty.cc:1053
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
absl::make_unique
memory_internal::MakeUniqueResult< T >::scalar make_unique(Args &&... args)
Definition: third_party/abseil-cpp/absl/memory/memory.h:168
bloaty::ThreadSafeIterIndex::mutex_
std::mutex mutex_
Definition: bloaty.cc:1352
bloaty::DataSourceDefinition::number
DataSource number
Definition: bloaty.cc:78
python_utils.upload_rbe_results.indent
indent
Definition: upload_rbe_results.py:183
bloaty::Bloaty::GetObjectFile
std::unique_ptr< ObjectFile > GetObjectFile(const std::string &filename) const
Definition: bloaty.cc:1460
env.new
def new
Definition: env.py:51
bloaty::Rollup::Subtract
void Subtract(const Rollup &other)
Definition: bloaty.cc:292
bloaty::__cxa_demangle
char * __cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status)
Definition: cxa_demangle.cpp:4927
bloaty::DataSource::kSegments
@ kSegments
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
bloaty::ArgParser::TryParseUint64Option
bool TryParseUint64Option(string_view flag, uint64_t *val)
Definition: bloaty.cc:1967
T
#define T(upbtypeconst, upbtype, ctype, default_value)
bloaty::Rollup::filtered_file_total_
int64_t filtered_file_total_
Definition: bloaty.cc:326
threads
static uv_thread_t * threads
Definition: threadpool.c:38
bloaty::DualMaps::KeysToString
std::string KeysToString(const std::vector< std::string > &keys)
Definition: bloaty.cc:1588
bloaty::RollupRow::filesize
int64_t filesize
Definition: bloaty.h:339
arena
grpc_core::ScopedArenaPtr arena
Definition: binder_transport_test.cc:237
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
bloaty::Bloaty::Bloaty
Bloaty(const InputFileFactory &factory, const Options &options)
Definition: bloaty.cc:1454
bloaty::ThreadSafeIterIndex
Definition: bloaty.cc:1319
bloaty::RangeMap
Definition: range_map.h:46
bloaty::RangeMap::DebugString
std::string DebugString() const
Definition: range_map.cc:138
bloaty::RangeSink::TranslateVMToFile
absl::string_view TranslateVMToFile(uint64_t address)
Definition: bloaty.cc:1282
bloaty::Bloaty::AddBuiltInSources
void AddBuiltInSources(const DataSourceDefinition(&sources)[T], const Options &options)
Definition: bloaty.cc:1394
bloaty::DataSourceDefinition::name
const char * name
Definition: bloaty.cc:79
absl::SimpleAtoi
ABSL_NAMESPACE_BEGIN ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type *out)
Definition: abseil-cpp/absl/strings/numbers.h:271
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
start
static uint64_t start
Definition: benchmark-pound.c:74
bloaty::ItaniumDemangle
std::string ItaniumDemangle(string_view symbol, DataSource source)
Definition: bloaty.cc:169
bloaty::RangeSink::AddFileRangeForVMAddr
void AddFileRangeForVMAddr(const char *analyzer, uint64_t label_from_vmaddr, absl::string_view file_range)
Definition: bloaty.cc:1112
bloaty::Bloaty::arena_
std::unique_ptr< google::protobuf::Arena > arena_
Definition: bloaty.cc:1451
bloaty::ThreadSafeIterIndex::TryGetError
bool TryGetError(std::string *error)
Definition: bloaty.cc:1339
absl::BytesToHexString
std::string BytesToHexString(absl::string_view from)
Definition: abseil-cpp/absl/strings/escaping.cc:940
bloaty::RangeSink::file_
const InputFile * file_
Definition: bloaty.h:224
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
bloaty::Rollup::operator=
Rollup & operator=(const Rollup &)=delete
bloaty::RollupOutput::PrintToCSV
void PrintToCSV(std::ostream *out, bool tabs) const
Definition: bloaty.cc:844
arena_
Arena * arena_
Definition: client_channel.cc:391
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
bloaty::RangeSink::kUnknownSize
static constexpr uint64_t kUnknownSize
Definition: bloaty.h:211
absl::StrJoin
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter &&fmt)
Definition: abseil-cpp/absl/strings/str_join.h:239
bloaty::RangeSink::outputs_
std::vector< std::pair< DualMap *, const NameMunger * > > outputs_
Definition: bloaty.h:228
bloaty::show
ShowDomain show
Definition: bloaty.cc:75
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
absl::string_view::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:277
bloaty::TryOpenPEFile
std::unique_ptr< ObjectFile > TryOpenPEFile(std::unique_ptr< InputFile > &file)
Definition: pe.cc:276
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
absl::base_internal::num_cpus
static ABSL_CONST_INIT int num_cpus
Definition: abseil-cpp/absl/base/internal/sysinfo.cc:343
THROW
#define THROW(msg)
Definition: bloaty/src/util.h:45
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
SIZE_MAX
#define SIZE_MAX
Definition: stdint-msvc2008.h:206
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
Z_OK
#define Z_OK
Definition: bloaty/third_party/zlib/zlib.h:177
bloaty::OutputOptions
Definition: bloaty.h:370
bloaty::ConfiguredDataSource::definition
const DataSourceDefinition & definition
Definition: bloaty.cc:1367
bloaty::OutputFormat::kCSV
@ kCSV
bloaty::CheckedAdd
void CheckedAdd(int64_t *accum, int64_t val)
Definition: bloaty.cc:124
bloaty::Rollup::file_total
int64_t file_total() const
Definition: bloaty.cc:319
text_format_test_wrapper.sep
sep
Definition: text_format_test_wrapper.py:34
bloaty::OutputFormat::kPrettyPrint
@ kPrettyPrint
bloaty::RollupRow::other_count
int64_t other_count
Definition: bloaty.h:342
bloaty::Bloaty
Definition: bloaty.cc:1374
bloaty::RangeSink::RangeSink
RangeSink(const InputFile *file, const Options &options, DataSource data_source, const DualMap *translator, google::protobuf::Arena *arena)
Definition: bloaty.cc:999
bloaty::Bloaty::InputFileInfo::filename_
std::string filename_
Definition: bloaty.cc:1443
bloaty::ReImpl::Extract
static ABSL_ATTRIBUTE_NORETURN bool Extract(std::string, const ReImpl &, std::string, std::string *)
Definition: bloaty/src/re.h:70
bloaty::Bloaty::EffectiveSymbolSource
static DataSource EffectiveSymbolSource(const Options &options)
Definition: bloaty.cc:1408
bloaty::NameMunger
Definition: bloaty.h:236
bloaty::ParseOptions
bool ParseOptions(bool skip_unknown, int *argc, char **argv[], Options *options, OutputOptions *output_options, std::string *error)
Definition: bloaty.cc:2138
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
bloaty::DoParseOptions
bool DoParseOptions(bool skip_unknown, int *argc, char **argv[], Options *options, OutputOptions *output_options)
Definition: bloaty.cc:1990
bloaty::Rollup::filtered_vm_total_
int64_t filtered_vm_total_
Definition: bloaty.cc:325
bloaty::RangeSink::data_source_
DataSource data_source_
Definition: bloaty.h:226
bloaty::OutputOptions::output_format
OutputFormat output_format
Definition: bloaty.h:371
bloaty::ReImpl::PartialMatch
static ABSL_ATTRIBUTE_NORETURN bool PartialMatch(const std::string &, const ReImpl &, A &&...)
Definition: bloaty/src/re.h:74
bloaty::ReImpl::ok
bool ok()
Definition: bloaty/src/re.h:67
bloaty::InputFile::data_
absl::string_view data_
Definition: bloaty.h:84
bloaty::RollupOutput::toplevel_row_
RollupRow toplevel_row_
Definition: bloaty.h:402
bloaty::ConfiguredDataSource
Definition: bloaty.cc:1361
bloaty::Bloaty::DisassembleFunction
void DisassembleFunction(string_view function, const Options &options, RollupOutput *output)
Definition: bloaty.cc:1828
arg
Definition: cmdline.cc:40
bloaty::RollupRow::sorted_children
std::vector< RollupRow > sorted_children
Definition: bloaty.h:346
number
int32_t number
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:850
bloaty::ReImpl
Definition: bloaty/src/re.h:63
bloaty::RollupOutput::PrintTreeToCSV
void PrintTreeToCSV(const RollupRow &row, std::vector< std::string > parent_labels, std::ostream *out, bool tabs) const
Definition: bloaty.cc:826
bloaty::ThreadSafeIterIndex::error_
std::string error_
Definition: bloaty.cc:1351
close
#define close
Definition: test-fs.c:48
googletest-filter-unittest.child
child
Definition: bloaty/third_party/googletest/googletest/test/googletest-filter-unittest.py:62
bloaty::DataSource::kCompileUnits
@ kCompileUnits
bloaty::Bloaty::base_files_
std::vector< InputFileInfo > base_files_
Definition: bloaty.cc:1447
bloaty::DualMaps
Definition: bloaty.cc:1542
bloaty::ConfiguredDataSource::effective_source
DataSource effective_source
Definition: bloaty.cc:1370
bloaty::Rollup
Definition: bloaty.cc:253
bloaty::DataSource::kInlines
@ kInlines
gen_synthetic_protos.base
base
Definition: gen_synthetic_protos.py:31
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
bloaty::DataSource
DataSource
Definition: bloaty.h:52
bloaty::Bloaty::debug_files_
std::map< std::string, std::string > debug_files_
Definition: bloaty.cc:1448
min
#define min(a, b)
Definition: qsort.h:83
bloaty::Bloaty::AddDataSource
void AddDataSource(const std::string &name)
Definition: bloaty.cc:1531
bloaty::Bloaty::options_
const Options options_
Definition: bloaty.cc:1430
bloaty::ArgParser::argv_
std::vector< char * > argv_
Definition: bloaty.cc:1984
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
google::protobuf::io::IstreamInputStream
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h:216
bloaty::RangeMap::Translate
bool Translate(uint64_t addr, uint64_t *translated) const
Definition: range_map.cc:87
bloaty::ShowDomain::kShowBoth
@ kShowBoth
bloaty::Rollup::vm_total_
int64_t vm_total_
Definition: bloaty.cc:323
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
bloaty::RollupRow::name
std::string name
Definition: bloaty.h:337
bloaty::DualMap
Definition: bloaty.h:312
bloaty::ArgParser::index_
int index_
Definition: bloaty.cc:1987
re.h
bloaty::Rollup::AddSizes
void AddSizes(const std::vector< std::string > &names, uint64_t size, bool is_vmsize)
Definition: bloaty.cc:262
bloaty::TryOpenELFFile
std::unique_ptr< ObjectFile > TryOpenELFFile(std::unique_ptr< InputFile > &file)
Definition: elf.cc:1403
bloaty::MmapInputFile::~MmapInputFile
~MmapInputFile() override
Definition: bloaty.cc:912
bloaty::DualMaps::PrintVMMaps
void PrintVMMaps()
Definition: bloaty.cc:1586
bloaty::RollupOutput::PrettyPrintTree
void PrettyPrintTree(const RollupRow &row, size_t indent, const OutputOptions &options, std::ostream *out) const
Definition: bloaty.cc:734
bloaty::TryOpenWebAssemblyFile
std::unique_ptr< ObjectFile > TryOpenWebAssemblyFile(std::unique_ptr< InputFile > &file)
Definition: webassembly.cc:380
bloaty::FileDescriptor
Definition: bloaty.cc:872
bloaty::RollupRow::vmsize
int64_t vmsize
Definition: bloaty.h:338
bloaty::Rollup::Percent
static double Percent(int64_t part, int64_t whole)
Definition: bloaty.cc:386
value
const char * value
Definition: hpack_parser_table.cc:165
bloaty::ArgParser::out_argc_
int * out_argc_
Definition: bloaty.cc:1985
bloaty::Rollup::file_total_
int64_t file_total_
Definition: bloaty.cc:324
bloaty::ArgParser::ConsumeAndSaveArg
void ConsumeAndSaveArg()
Definition: bloaty.cc:1914
verbose
bool verbose
Definition: bloaty/third_party/protobuf/conformance/conformance_cpp.cc:70
bloaty::Rollup::filter_regex_
const ReImpl * filter_regex_
Definition: bloaty.cc:328
bloaty::RangeSink::ContainsVerboseVMAddr
bool ContainsVerboseVMAddr(uint64_t vmaddr, uint64_t vmsize)
Definition: bloaty.cc:1010
bloaty::RangeSink::AddVMRangeForVMAddr
void AddVMRangeForVMAddr(const char *analyzer, uint64_t label_from_vmaddr, uint64_t addr, uint64_t size)
Definition: bloaty.cc:1170
bloaty::RangeSink::ZlibDecompress
absl::string_view ZlibDecompress(absl::string_view contents, uint64_t uncompressed_size)
Definition: bloaty.cc:1292
testing::internal::fmt
GTEST_API_ const char * fmt
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1808
bloaty::FileDescriptor::fd_
int fd_
Definition: bloaty.cc:885
bloaty::DualMaps::DualMaps
DualMaps()
Definition: bloaty.cc:1544
bloaty::DualMaps::PrintMaps
void PrintMaps(const std::vector< const RangeMap * > maps)
Definition: bloaty.cc:1570
gen_build_yaml.sources
sources
Definition: src/boringssl/gen_build_yaml.py:27
bloaty::DualMaps::AppendMap
DualMap * AppendMap()
Definition: bloaty.cc:1549
bloaty::DualMap::file_map
RangeMap file_map
Definition: bloaty.h:314
bloaty::DataSource::kSymbols
@ kSymbols
bloaty::usage
const char usage[]
Definition: bloaty.cc:1843
BLOATY_UNREACHABLE
#define BLOATY_UNREACHABLE()
Definition: bloaty/src/util.h:53
bloaty::ArgParser::out_argv_
char *** out_argv_
Definition: bloaty.cc:1986
options_
DebugStringOptions options_
Definition: bloaty/third_party/protobuf/src/google/protobuf/descriptor.cc:2390
bloaty::RangeMap::ForEachRange
void ForEachRange(Func func) const
Definition: range_map.h:138
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
bloaty::DataSource::kInputFiles
@ kInputFiles
absl::string_view::remove_prefix
ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n)
Definition: abseil-cpp/absl/strings/string_view.h:344
bloaty::ThreadSafeIterIndex::ThreadSafeIterIndex
ThreadSafeIterIndex(int max)
Definition: bloaty.cc:1321
bloaty::ConfiguredDataSource::munger
std::unique_ptr< NameMunger > munger
Definition: bloaty.cc:1371
bloaty::MmapInputFile::operator=
MmapInputFile & operator=(const MmapInputFile &)=delete
bloaty::NameMunger::AddRegex
void AddRegex(const std::string &regex, const std::string &replacement)
Definition: bloaty.cc:208
bloaty::debug_vmaddr
uint64_t debug_vmaddr
Definition: bloaty.cc:1007
bloaty::RangeSink::FileContainsPointer
bool FileContainsPointer(const void *ptr) const
Definition: bloaty.h:214
bloaty::DualMaps::PrintFileMaps
void PrintFileMaps()
Definition: bloaty.cc:1585
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
absl::debugging_internal::Demangle
bool Demangle(const char *mangled, char *out, int out_size)
Definition: abseil-cpp/absl/debugging/internal/demangle.cc:1950
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
bloaty::ArgParser
Definition: bloaty.cc:1890
bloaty::DualMaps::VmMaps
std::vector< const RangeMap * > VmMaps() const
Definition: bloaty.cc:1611
bloaty::RangeSink::IsVerboseForVMRange
bool IsVerboseForVMRange(uint64_t vmaddr, uint64_t vmsize)
Definition: bloaty.cc:1022
bloaty::ThreadSafeIterIndex::TryGetNext
bool TryGetNext(int *index)
Definition: bloaty.cc:1323
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
string_view
absl::string_view string_view
Definition: attr.cc:22
bloaty::Bloaty::InputFileInfo
Definition: bloaty.cc:1442
bloaty::RangeSink::options_
const Options options_
Definition: bloaty.h:225
num_threads
static volatile int num_threads
Definition: benchmark-thread.c:30
tests.google.protobuf.internal.message_test.isinf
def isinf(val)
Definition: bloaty/third_party/protobuf/python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/message_test.py:68
bloaty::ShowDomain::kShowVM
@ kShowVM
bloaty::DisassemblyInfo
Definition: bloaty.h:317
ares::ShowFile
static void ShowFile(const char *filename)
Definition: dns-dump.cc:16
file::size
int size
Definition: bloaty/third_party/zlib/examples/gzappend.c:172
bloaty::DualMaps::PrintMapRow
void PrintMapRow(string_view str, uint64_t start, uint64_t end, int hex_digits)
Definition: bloaty.cc:1602
bloaty::DualMaps::maps_
std::vector< std::unique_ptr< DualMap > > maps_
Definition: bloaty.cc:1627
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: bloaty/third_party/zlib/contrib/minizip/iowin32.c:21
bloaty::TryOpenMachOFile
std::unique_ptr< ObjectFile > TryOpenMachOFile(std::unique_ptr< InputFile > &file)
Definition: macho.cc:610
bloaty::data_sources
constexpr DataSourceDefinition data_sources[]
Definition: bloaty.cc:83
ok
bool ok
Definition: async_end2end_test.cc:197
THROWF
#define THROWF(...)
Definition: bloaty/src/util.h:46
arg
struct arg arg
data_
std::string data_
Definition: cord_rep_btree_navigator_test.cc:84
bloaty::Bloaty::AddDebugFilename
void AddDebugFilename(const std::string &filename)
Definition: bloaty.cc:1495
bloaty::ArgParser::ConsumeArg
string_view ConsumeArg()
Definition: bloaty.cc:1908
bloaty::RangeSink::AddRange
void AddRange(const char *analyzer, absl::string_view name, uint64_t vmaddr, uint64_t vmsize, uint64_t fileoff, uint64_t filesize)
Definition: bloaty.cc:1232
bloaty::RollupOutput::Print
void Print(const OutputOptions &options, std::ostream *out)
Definition: bloaty.cc:673
absl::Substitute
ABSL_MUST_USE_RESULT std::string Substitute(absl::string_view format)
Definition: abseil-cpp/absl/strings/substitute.h:506
bloaty::ArgParser::ArgParser
ArgParser(int *argc, char **argv[])
Definition: bloaty.cc:1892
bloaty::ArgParser::Arg
string_view Arg()
Definition: bloaty.cc:1903
bloaty::FileDescriptor::~FileDescriptor
~FileDescriptor()
Definition: bloaty.cc:876
bloaty::ThreadSafeIterIndex::index_
std::atomic< int > index_
Definition: bloaty.cc:1350
input
std::string input
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:197
bloaty::Bloaty::InputFileInfo::build_id_
std::string build_id_
Definition: bloaty.cc:1444
bloaty::Bloaty::source_names_
std::vector< std::string > source_names_
Definition: bloaty.cc:1440
bloaty::Bloaty::ScanAndRollupFiles
void ScanAndRollupFiles(const std::vector< std::string > &filenames, std::vector< std::string > *build_ids, Rollup *rollup) const
Definition: bloaty.cc:1711
bloaty::CSVEscape
static std::string CSVEscape(string_view str)
Definition: bloaty.cc:140
open
#define open
Definition: test-fs.c:46
bloaty::ThreadSafeIterIndex::max_
const int max_
Definition: bloaty.cc:1353
bloaty::ArgParser::TryParseIntegerOption
bool TryParseIntegerOption(string_view flag, int *val)
Definition: bloaty.cc:1954
bloaty::RangeSink::~RangeSink
~RangeSink()
Definition: bloaty.cc:1005
bloaty::ShowDomain::kShowFile
@ kShowFile
stat
#define stat
Definition: test-fs.c:50
bloaty::RangeSink::AddVMRangeAllowAlias
void AddVMRangeAllowAlias(const char *analyzer, uint64_t vmaddr, uint64_t size, const std::string &name)
Definition: bloaty.cc:1218
bloaty::Rollup::Add
void Add(const Rollup &other)
Definition: bloaty.cc:306
bloaty::DataSource::kFullSymbols
@ kFullSymbols
contains
static int contains(grpc_timer_heap *pq, grpc_timer *el)
Definition: iomgr/timer_heap_test.cc:43
bloaty::Rollup::AddInternal
void AddInternal(const std::vector< std::string > &names, size_t i, uint64_t size, bool is_vmsize)
Definition: bloaty.cc:345
iter
Definition: test_winkernel.cpp:47
bloaty::RollupRow::Compare
static bool Compare(const RollupRow &a, const RollupRow &b)
Definition: bloaty.h:348
bloaty::RangeSink::AddVMRangeIgnoreDuplicate
void AddVMRangeIgnoreDuplicate(const char *analyzer, uint64_t vmaddr, uint64_t size, const std::string &name)
Definition: bloaty.cc:1225
bloaty::InputFile::data
absl::string_view data() const
Definition: bloaty.h:78
util.h
GetFileSizeEx
WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize)
google::protobuf::TextFormat::Merge
static bool Merge(io::ZeroCopyInputStream *input, Message *output)
Definition: bloaty/third_party/protobuf/src/google/protobuf/text_format.cc:1480
bloaty::DataSource::kRawSymbols
@ kRawSymbols
bloaty::RollupRow::vmpercent
double vmpercent
Definition: bloaty.h:344
ch
char ch
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3621
bloaty::Rollup::empty_
static Rollup * empty_
Definition: bloaty.cc:334
bloaty::RollupRow::filtered_filesize
int64_t filtered_filesize
Definition: bloaty.h:341
WARN
#define WARN(...)
Definition: bloaty/src/util.h:47
bloaty::Rollup::Rollup
Rollup()
Definition: bloaty.cc:255
bloaty::ShowDomain
ShowDomain
Definition: bloaty.h:364
bloaty::Bloaty::sources_
std::vector< ConfiguredDataSource * > sources_
Definition: bloaty.cc:1439
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
bloaty::Rollup::CreateRollupOutput
void CreateRollupOutput(const Options &options, RollupOutput *output) const
Definition: bloaty.cc:269
bloaty::DualMaps::base_map
DualMap * base_map()
Definition: bloaty.cc:1608
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
bloaty::MmapInputFileFactory::OpenFile
std::unique_ptr< InputFile > OpenFile(const std::string &filename) const override
Definition: bloaty.cc:919
bloaty::RollupRow
Definition: bloaty.h:334
bloaty::Bloaty::all_known_sources_
std::map< std::string, std::unique_ptr< ConfiguredDataSource > > all_known_sources_
Definition: bloaty.cc:1435
bloaty::OutputOptions::max_label_len
size_t max_label_len
Definition: bloaty.h:372
bloaty::RollupOutput::IsSame
static bool IsSame(const std::string &a, const std::string &b)
Definition: bloaty.cc:722
absl::string_view::data
constexpr const_pointer data() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:336
to_string
static bool to_string(zval *from)
Definition: protobuf/php/ext/google/protobuf/convert.c:333
absl::str_format_internal::LengthMod::h
@ h
bloaty::RangeSink::ContainsVerboseFileOffset
bool ContainsVerboseFileOffset(uint64_t fileoff, uint64_t filesize)
Definition: bloaty.cc:1016
google_benchmark.option
option
Definition: third_party/benchmark/bindings/python/google_benchmark/__init__.py:115
pair
std::pair< std::string, std::string > pair
Definition: abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc:78
absl::string_view::substr
constexpr string_view substr(size_type pos=0, size_type n=npos) const
Definition: abseil-cpp/absl/strings/string_view.h:399
bloaty::RollupOutput::PrettyPrintRow
void PrettyPrintRow(const RollupRow &row, size_t indent, const OutputOptions &options, std::ostream *out) const
Definition: bloaty.cc:695
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
bloaty::DataSourceDefinition::description
const char * description
Definition: bloaty.cc:80
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
google
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:11
bloaty::RangeMap::ComputeRollup
static void ComputeRollup(const std::vector< const RangeMap * > &range_maps, Func func)
Definition: range_map.h:251
bloaty::RollupOutput::PrintRowToCSV
void PrintRowToCSV(const RollupRow &row, std::vector< std::string > parent_labels, std::ostream *out, bool tabs) const
Definition: bloaty.cc:811
bloaty::RangeSink::TranslateFileToVM
uint64_t TranslateFileToVM(const char *ptr)
Definition: bloaty.cc:1269
absl::EndsWith
bool EndsWith(absl::string_view text, absl::string_view suffix) noexcept
Definition: third_party/abseil-cpp/absl/strings/match.h:68
bloaty::InputFile
Definition: bloaty.h:70
bloaty::RangeSink::AddOutput
void AddOutput(DualMap *map, const NameMunger *munger)
Definition: bloaty.cc:1084
bloaty::RollupRow::filtered_vmsize
int64_t filtered_vmsize
Definition: bloaty.h:340
bloaty::RollupOutput::disassembly_
std::string disassembly_
Definition: bloaty.h:403
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
bloaty::OutputOptions::show
ShowDomain show
Definition: bloaty.h:373
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
bloaty::ThreadSafeIterIndex::Abort
void Abort(string_view error)
Definition: bloaty.cc:1333
common
Definition: bloaty/third_party/googletest/googletest/scripts/common.py:1
bloaty::Rollup::SetFilterRegex
void SetFilterRegex(const ReImpl *regex)
Definition: bloaty.cc:287
bloaty::FileDescriptor::FileDescriptor
FileDescriptor(int fd)
Definition: bloaty.cc:874
bloaty::Bloaty::AddFilename
void AddFilename(const std::string &filename, bool base_file)
Definition: bloaty.cc:1484
bloaty::DataSource::kSections
@ kSections
bloaty::ArgParser::IsDone
bool IsDone()
Definition: bloaty.cc:1901
bloaty::Rollup::GetEmpty
static Rollup * GetEmpty()
Definition: bloaty.cc:336
bloaty::InputFileFactory
Definition: bloaty.h:87
absl::ConsumePrefix
ABSL_NAMESPACE_BEGIN bool ConsumePrefix(absl::string_view *str, absl::string_view expected)
Definition: abseil-cpp/absl/strings/strip.h:46
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:48