_ZN8perfetto4base13ignore_resultIJA48_cmEEEvDpRKT_:
  157|     10|inline void ignore_result(const T&...) {}
_ZN8perfetto4base13ignore_resultIJA53_cmEEEvDpRKT_:
  157|     12|inline void ignore_result(const T&...) {}
_ZN8perfetto4base13ignore_resultIJA46_cmEEEvDpRKT_:
  157|     37|inline void ignore_result(const T&...) {}
_ZN8perfetto4base13ignore_resultIJA47_cmjEEEvDpRKT_:
  157|     41|inline void ignore_result(const T&...) {}
_ZN8perfetto4base13ignore_resultIJA65_cEEEvDpRKT_:
  157|    348|inline void ignore_result(const T&...) {}
_ZN8perfetto4base13ignore_resultIJA72_cjmEEEvDpRKT_:
  157|     51|inline void ignore_result(const T&...) {}

_ZN8perfetto4base6HasherC2Ev:
   37|  1.33k|  constexpr Hasher() = default;
_ZN8perfetto4base6Hasher6UpdateIjTnNSt3__19enable_ifIXsr3std13is_arithmeticIT_EE5valueEbE4typeELb1EEEvS5_:
   43|  20.7M|  void Update(T data) {
   44|  20.7M|    Update(reinterpret_cast<const char*>(&data), sizeof(data));
   45|  20.7M|  }
_ZN8perfetto4base6Hasher6UpdateEPKcm:
   56|  20.7M|  constexpr void Update(const char* data, size_t size) {
   57|   103M|    for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (57:24): [True: 82.8M, False: 20.7M]
  ------------------
   58|  82.8M|      result_ ^= static_cast<uint8_t>(data[i]);
   59|       |      // Note: Arithmetic overflow of unsigned integers is well defined in C++
   60|       |      // standard unlike signed integers.
   61|       |      // https://stackoverflow.com/a/41280273
   62|  82.8M|      result_ *= kFnv1a64Prime;
   63|  82.8M|    }
   64|  20.7M|  }
_ZNK8perfetto4base6Hasher6digestEv:
   79|  1.33k|  constexpr uint64_t digest() const { return result_; }

_ZN8perfetto4base7AlignUpILm4096EEEmm:
   99|    242|constexpr size_t AlignUp(size_t size) {
  100|    242|  static_assert((alignment & (alignment - 1)) == 0, "alignment must be a pow2");
  101|    242|  return AlignUp(size, alignment);
  102|    242|}
_ZN8perfetto4base7AlignUpEmm:
   92|    242|inline constexpr size_t AlignUp(size_t size, size_t alignment) {
   93|    242|  return (size + alignment - 1) & ~(alignment - 1);
   94|    242|}

_ZN9protozero16PackedBufferBaseC2Ev:
   50|    475|  PackedBufferBase() { Reset(); }
_ZN9protozero12PackedVarInt6AppendIjEEvT_:
   92|  3.56M|  void Append(T value) {
   93|  3.56M|    GrowIfNeeded();
   94|  3.56M|    write_ptr_ = proto_utils::WriteVarInt(value, write_ptr_);
   95|  3.56M|  }
_ZN9protozero16PackedBufferBase12GrowIfNeededEv:
   67|  3.56M|  void GrowIfNeeded() {
   68|  3.56M|    PERFETTO_DCHECK(write_ptr_ >= storage_begin_ && write_ptr_ <= storage_end_);
   69|  3.56M|    if (PERFETTO_UNLIKELY(write_ptr_ + kMaxElementSize > storage_end_)) {
  ------------------
  |  |   24|  3.56M|#define PERFETTO_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
  |  |  ------------------
  |  |  |  Branch (24:32): [True: 242, False: 3.56M]
  |  |  ------------------
  ------------------
   70|    242|      GrowSlowpath();
   71|    242|    }
   72|  3.56M|  }
_ZNK9protozero16PackedBufferBase4dataEv:
   60|    475|  const uint8_t* data() const { return storage_begin_; }
_ZNK9protozero16PackedBufferBase4sizeEv:
   62|    475|  size_t size() const {
   63|    475|    return static_cast<size_t>(write_ptr_ - storage_begin_);
   64|    475|  }

_ZN9protozero27PackedRepeatedFieldIteratorILNS_11proto_utils13ProtoWireTypeE0EjEC2EPKhmPb:
  178|    881|      : data_end_(data_begin ? data_begin + size : nullptr),
  ------------------
  |  Branch (178:19): [True: 881, False: 0]
  ------------------
  179|    881|        read_ptr_(data_begin),
  180|    881|        parse_error_(parse_error_ptr) {
  181|    881|    using proto_utils::ProtoWireType;
  182|    881|    static_assert(wire_type == ProtoWireType::kVarInt ||
  183|    881|                      wire_type == ProtoWireType::kFixed32 ||
  184|    881|                      wire_type == ProtoWireType::kFixed64,
  185|    881|                  "invalid type");
  186|       |
  187|    881|    PERFETTO_DCHECK(parse_error_ptr);
  188|       |
  189|       |    // Either the field is unset (and there are no data pointer), or the field
  190|       |    // is set with a zero length payload. Mark the iterator as invalid in both
  191|       |    // cases.
  192|    881|    if (size == 0) {
  ------------------
  |  Branch (192:9): [True: 0, False: 881]
  ------------------
  193|      0|      curr_value_valid_ = false;
  194|      0|      return;
  195|      0|    }
  196|       |
  197|    881|    if ((wire_type == ProtoWireType::kFixed32 && (size % 4) != 0) ||
  ------------------
  |  Branch (197:10): [Folded - Ignored]
  |  Branch (197:50): [True: 0, False: 0]
  ------------------
  198|    881|        (wire_type == ProtoWireType::kFixed64 && (size % 8) != 0)) {
  ------------------
  |  Branch (198:10): [Folded - Ignored]
  |  Branch (198:50): [True: 0, False: 0]
  ------------------
  199|      0|      *parse_error_ = true;
  200|      0|      curr_value_valid_ = false;
  201|      0|      return;
  202|      0|    }
  203|       |
  204|    881|    ++(*this);
  205|    881|  }
_ZNK9protozero27PackedRepeatedFieldIteratorILNS_11proto_utils13ProtoWireTypeE0EjEcvbEv:
  208|  17.2M|  explicit operator bool() const { return curr_value_valid_; }
_ZN9protozero27PackedRepeatedFieldIteratorILNS_11proto_utils13ProtoWireTypeE0EjEppEv:
  210|  17.2M|  PackedRepeatedFieldIterator& operator++() {
  211|  17.2M|    using proto_utils::ProtoWireType;
  212|       |
  213|  17.2M|    if (PERFETTO_UNLIKELY(!curr_value_valid_))
  ------------------
  |  |   24|  17.2M|#define PERFETTO_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
  |  |  ------------------
  |  |  |  Branch (24:32): [True: 0, False: 17.2M]
  |  |  ------------------
  ------------------
  214|      0|      return *this;
  215|       |
  216|  17.2M|    if (PERFETTO_UNLIKELY(read_ptr_ == data_end_)) {
  ------------------
  |  |   24|  17.2M|#define PERFETTO_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
  |  |  ------------------
  |  |  |  Branch (24:32): [True: 858, False: 17.2M]
  |  |  ------------------
  ------------------
  217|    858|      curr_value_valid_ = false;
  218|    858|      return *this;
  219|    858|    }
  220|       |
  221|  17.2M|    if (wire_type == ProtoWireType::kVarInt) {
  ------------------
  |  Branch (221:9): [Folded - Ignored]
  ------------------
  222|  17.2M|      uint64_t new_value = 0;
  223|  17.2M|      const uint8_t* new_pos =
  224|  17.2M|          proto_utils::ParseVarInt(read_ptr_, data_end_, &new_value);
  225|       |
  226|  17.2M|      if (PERFETTO_UNLIKELY(new_pos == read_ptr_)) {
  ------------------
  |  |   24|  17.2M|#define PERFETTO_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
  |  |  ------------------
  |  |  |  Branch (24:32): [True: 23, False: 17.2M]
  |  |  ------------------
  ------------------
  227|       |        // Failed to decode the varint (probably incomplete buffer).
  228|     23|        *parse_error_ = true;
  229|     23|        curr_value_valid_ = false;
  230|  17.2M|      } else {
  231|  17.2M|        read_ptr_ = new_pos;
  232|  17.2M|        curr_value_ = static_cast<CppType>(new_value);
  233|  17.2M|      }
  234|  17.2M|    } else {  // kFixed32 or kFixed64
  235|      0|      constexpr size_t kStep = wire_type == ProtoWireType::kFixed32 ? 4 : 8;
  ------------------
  |  Branch (235:32): [Folded - Ignored]
  ------------------
  236|       |
  237|       |      // NB: the raw buffer is not guaranteed to be aligned, so neither are
  238|       |      // these copies.
  239|      0|      memcpy(&curr_value_, read_ptr_, sizeof(CppType));
  240|      0|      read_ptr_ += kStep;
  241|      0|    }
  242|       |
  243|  17.2M|    return *this;
  244|  17.2M|  }
_ZNK9protozero27PackedRepeatedFieldIteratorILNS_11proto_utils13ProtoWireTypeE0EjEdeEv:
  207|  17.2M|  const CppType operator*() const { return curr_value_; }

_ZN9protozero11proto_utils11WriteVarIntIjEEPhT_S2_:
  209|  3.56M|inline uint8_t* WriteVarInt(T value, uint8_t* target) {
  210|  3.56M|  auto unsigned_value = ExtendValueForVarIntSerialization(value);
  211|       |
  212|  13.4M|  while (unsigned_value >= 0x80) {
  ------------------
  |  Branch (212:10): [True: 9.86M, False: 3.56M]
  ------------------
  213|  9.86M|    *target++ = static_cast<uint8_t>(unsigned_value) | 0x80;
  214|  9.86M|    unsigned_value >>= 7;
  215|  9.86M|  }
  216|  3.56M|  *target = static_cast<uint8_t>(unsigned_value);
  217|  3.56M|  return target + 1;
  218|  3.56M|}
_ZN9protozero11proto_utils33ExtendValueForVarIntSerializationIjEENSt3__113make_unsignedINS2_11conditionalIXsr3std11is_unsignedIT_EE5valueES5_lE4typeEE4typeES5_:
  185|  3.56M|    type {
  186|       |  // If value is <= 0 we must first sign extend to int64_t (see [1]).
  187|       |  // Finally we always cast to an unsigned value to to avoid arithmetic
  188|       |  // (sign expanding) shifts in the while loop.
  189|       |  // [1]: "If you use int32 or int64 as the type for a negative number, the
  190|       |  // resulting varint is always ten bytes long".
  191|       |  // - developers.google.com/protocol-buffers/docs/encoding
  192|       |  // So for each input type we do the following casts:
  193|       |  // uintX_t -> uintX_t -> uintX_t
  194|       |  // int8_t  -> int64_t -> uint64_t
  195|       |  // int16_t -> int64_t -> uint64_t
  196|       |  // int32_t -> int64_t -> uint64_t
  197|       |  // int64_t -> int64_t -> uint64_t
  198|  3.56M|  using MaybeExtendedType =
  199|  3.56M|      typename std::conditional<std::is_unsigned<T>::value, T, int64_t>::type;
  200|  3.56M|  using UnsignedType = typename std::make_unsigned<MaybeExtendedType>::type;
  201|       |
  202|  3.56M|  MaybeExtendedType extended_value = static_cast<MaybeExtendedType>(value);
  203|  3.56M|  UnsignedType unsigned_value = static_cast<UnsignedType>(extended_value);
  204|       |
  205|  3.56M|  return unsigned_value;
  206|  3.56M|}
_ZN9protozero11proto_utils11ParseVarIntEPKhS2_Pm:
  257|  17.2M|                                  uint64_t* out_value) {
  258|  17.2M|  return PerfettoPbParseVarInt(start, end, out_value);
  259|  17.2M|}

filter_bytecode_parser.cc:_ZL21PerfettoPbParseVarIntPKhS0_Pm:
   99|  17.2M|                                                   uint64_t* out_value) {
  100|  17.2M|  const uint8_t* pos = start;
  101|  17.2M|  uint64_t value = 0;
  102|  27.1M|  for (uint32_t shift = 0; pos < end && shift < 64u; shift += 7) {
  ------------------
  |  Branch (102:28): [True: 27.1M, False: 15]
  |  Branch (102:41): [True: 27.1M, False: 8]
  ------------------
  103|       |    // Cache *pos into |cur_byte| to prevent that the compiler dereferences the
  104|       |    // pointer twice (here and in the if() below) due to char* aliasing rules.
  105|  27.1M|    uint8_t cur_byte = *pos++;
  106|  27.1M|    value |= PERFETTO_STATIC_CAST(uint64_t, cur_byte & 0x7f) << shift;
  ------------------
  |  |   33|  27.1M|#define PERFETTO_STATIC_CAST(TYPE, VAL) static_cast<TYPE>(VAL)
  ------------------
  107|  27.1M|    if ((cur_byte & 0x80) == 0) {
  ------------------
  |  Branch (107:9): [True: 17.2M, False: 9.86M]
  ------------------
  108|       |      // In valid cases we get here.
  109|  17.2M|      *out_value = value;
  110|  17.2M|      return pos;
  111|  17.2M|    }
  112|  27.1M|  }
  113|     23|  *out_value = 0;
  114|     23|  return start;
  115|  17.2M|}

utils.cc:_ZN12_GLOBAL__N_121CheckCpuOptimizationsEv:
  113|      2|CheckCpuOptimizations() {
  114|      2|  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
  115|      2|  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
  ------------------
  |  |   98|      2|  asm("mov %%rbx, %%rdi\n"                          \
  |  |   99|      2|      "cpuid\n"                                     \
  |  |  100|      2|      "xchg %%rdi, %%rbx\n"                         \
  |  |  101|      2|      : "=a"(a), "=D"(b), "=c"(c), "=d"(d)          \
  |  |  102|      2|      : "a"(a_inp), "2"(c_inp))
  ------------------
  116|       |
  117|      2|  static constexpr uint64_t xcr0_xmm_mask = 0x2;
  118|      2|  static constexpr uint64_t xcr0_ymm_mask = 0x4;
  119|      2|  static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
  120|       |
  121|      2|  const bool have_popcnt = ecx & (1u << 23);
  122|      2|  const bool have_sse4_2 = ecx & (1u << 20);
  123|      2|  const bool have_avx =
  124|       |      // Does the OS save/restore XMM and YMM state?
  125|      2|      (ecx & (1u << 27)) &&  // OS support XGETBV.
  ------------------
  |  Branch (125:7): [True: 2, False: 0]
  ------------------
  126|      2|      (ecx & (1u << 28)) &&  // AVX supported in hardware
  ------------------
  |  Branch (126:7): [True: 2, False: 0]
  ------------------
  127|      2|      ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
  ------------------
  |  Branch (127:7): [True: 2, False: 0]
  ------------------
  128|       |
  129|       |  // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
  130|       |  // (See Intel 64 and IA-32 Architectures Software Developer's Manual
  131|       |  //  Volume 2A: Instruction Set Reference, A-M CPUID).
  132|      2|  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
  ------------------
  |  |   98|      2|  asm("mov %%rbx, %%rdi\n"                          \
  |  |   99|      2|      "cpuid\n"                                     \
  |  |  100|      2|      "xchg %%rdi, %%rbx\n"                         \
  |  |  101|      2|      : "=a"(a), "=D"(b), "=c"(c), "=d"(d)          \
  |  |  102|      2|      : "a"(a_inp), "2"(c_inp))
  ------------------
  133|      2|  const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
  ------------------
  |  Branch (133:26): [True: 2, False: 0]
  |  Branch (133:38): [True: 2, False: 0]
  ------------------
  134|      2|  const bool have_bmi = (ebx >> 3) & 0x1;
  135|      2|  const bool have_bmi2 = (ebx >> 8) & 0x1;
  136|       |
  137|      2|  if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
  ------------------
  |  Branch (137:7): [True: 0, False: 2]
  |  Branch (137:23): [True: 0, False: 2]
  |  Branch (137:39): [True: 0, False: 2]
  |  Branch (137:53): [True: 0, False: 2]
  |  Branch (137:66): [True: 0, False: 2]
  ------------------
  138|      0|    fprintf(
  139|      0|        stderr,
  140|      0|        "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
  141|      0|        "AVX2.\n"
  142|       |#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  143|       |        "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
  144|       |        "See https://github.com/google/perfetto/issues/294 for more.\n"
  145|       |#endif
  146|      0|        "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
  147|      0|    _exit(126);
  148|      0|  }
  149|      2|}
utils.cc:_ZN12_GLOBAL__N_110GetXCR0EAXEv:
  104|      2|uint32_t GetXCR0EAX() {
  105|      2|  uint32_t eax = 0, edx = 0;
  106|      2|  asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
  107|      2|  return eax;
  108|      2|}

_ZN9protozero20FilterBytecodeParser5ResetEv:
   28|  1.50k|void FilterBytecodeParser::Reset() {
   29|  1.50k|  bool suppress = suppress_logs_for_fuzzer_;
   30|  1.50k|  *this = FilterBytecodeParser();
   31|  1.50k|  suppress_logs_for_fuzzer_ = suppress;
   32|  1.50k|}
_ZN9protozero20FilterBytecodeParser4LoadEPKvm:
   34|    881|bool FilterBytecodeParser::Load(const void* filter_data, size_t len) {
   35|    881|  Reset();
   36|    881|  bool res = LoadInternal(static_cast<const uint8_t*>(filter_data), len);
   37|       |  // If load fails, don't leave the parser in a half broken state.
   38|    881|  if (!res)
  ------------------
  |  Branch (38:7): [True: 627, False: 254]
  ------------------
   39|    627|    Reset();
   40|    881|  return res;
   41|    881|}
_ZN9protozero20FilterBytecodeParser12LoadInternalEPKhm:
   44|    881|                                        size_t len) {
   45|       |  // First unpack the varints into a plain uint32 vector, so it's easy to
   46|       |  // iterate through them and look ahead.
   47|    881|  std::vector<uint32_t> words;
   48|    881|  bool packed_parse_err = false;
   49|    881|  words.reserve(len);  // An overestimation, but avoids reallocations.
   50|    881|  using BytecodeDecoder =
   51|    881|      PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
   52|    881|                                  uint32_t>;
   53|  17.2M|  for (BytecodeDecoder it(bytecode_data, len, &packed_parse_err); it; ++it)
  ------------------
  |  Branch (53:67): [True: 17.2M, False: 881]
  ------------------
   54|  17.2M|    words.emplace_back(*it);
   55|       |
   56|    881|  if (packed_parse_err || words.empty())
  ------------------
  |  Branch (56:7): [True: 23, False: 858]
  |  Branch (56:27): [True: 0, False: 858]
  ------------------
   57|     23|    return false;
   58|       |
   59|    858|  perfetto::base::Hasher hasher;
   60|  17.1M|  for (size_t i = 0; i < words.size() - 1; ++i)
  ------------------
  |  Branch (60:22): [True: 17.1M, False: 858]
  ------------------
   61|  17.1M|    hasher.Update(words[i]);
   62|       |
   63|    858|  uint32_t expected_csum = static_cast<uint32_t>(hasher.digest());
   64|    858|  if (expected_csum != words.back()) {
  ------------------
  |  Branch (64:7): [True: 105, False: 753]
  ------------------
   65|    105|    if (!suppress_logs_for_fuzzer_) {
  ------------------
  |  Branch (65:9): [True: 0, False: 105]
  ------------------
   66|      0|      PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
   67|      0|                    expected_csum, words.back());
   68|      0|    }
   69|    105|    return false;
   70|    105|  }
   71|       |
   72|    753|  words.pop_back();  // Pop the checksum.
   73|       |
   74|       |  // Temporay storage for each message. Cleared on every END_OF_MESSAGE.
   75|    753|  std::vector<uint32_t> direct_indexed_fields;
   76|    753|  std::vector<uint32_t> ranges;
   77|    753|  uint32_t max_msg_index = 0;
   78|       |
   79|    753|  auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
   80|    753|    PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
   81|    753|    direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
   82|    753|                                          static_cast<size_t>(field_id) + 1));
   83|    753|    direct_indexed_fields[field_id] = kAllowed | msg_id;
   84|    753|  };
   85|       |
   86|    753|  auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
   87|    753|    PERFETTO_DCHECK(id_end > id_start);
   88|    753|    PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
   89|    753|    ranges.emplace_back(id_start);
   90|    753|    ranges.emplace_back(id_end);
   91|    753|    ranges.emplace_back(kAllowed | msg_id);
   92|    753|  };
   93|       |
   94|    753|  bool is_eom = true;
   95|  10.7M|  for (size_t i = 0; i < words.size(); ++i) {
  ------------------
  |  Branch (95:22): [True: 10.7M, False: 653]
  ------------------
   96|  10.7M|    const uint32_t word = words[i];
   97|  10.7M|    const bool has_next_word = i < words.size() - 1;
   98|  10.7M|    const uint32_t opcode = word & 0x7u;
   99|  10.7M|    const uint32_t field_id = word >> 3;
  100|       |
  101|  10.7M|    is_eom = opcode == kFilterOpcode_EndOfMessage;
  102|  10.7M|    if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
  ------------------
  |  Branch (102:9): [True: 7.38M, False: 3.34M]
  |  Branch (102:26): [True: 10, False: 7.38M]
  ------------------
  103|     10|      PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
  104|     10|      return false;
  105|     10|    }
  106|       |
  107|  10.7M|    if (opcode == kFilterOpcode_SimpleField ||
  ------------------
  |  Branch (107:9): [True: 710k, False: 10.0M]
  ------------------
  108|  10.7M|        opcode == kFilterOpcode_NestedField ||
  ------------------
  |  Branch (108:9): [True: 166k, False: 9.85M]
  ------------------
  109|  10.7M|        opcode == kFilterOpcode_FilterString) {
  ------------------
  |  Branch (109:9): [True: 566k, False: 9.28M]
  ------------------
  110|       |      // Field words are organized as follow:
  111|       |      // MSB: 1 if allowed, 0 if not allowed.
  112|       |      // Remaining bits:
  113|       |      //   Message index in the case of nested (non-simple) messages.
  114|       |      //   0x7f..e in the case of string fields which need filtering.
  115|       |      //   0x7f..f in the case of simple fields.
  116|  1.44M|      uint32_t msg_id;
  117|  1.44M|      if (opcode == kFilterOpcode_SimpleField) {
  ------------------
  |  Branch (117:11): [True: 710k, False: 732k]
  ------------------
  118|   710k|        msg_id = kSimpleField;
  119|   732k|      } else if (opcode == kFilterOpcode_FilterString) {
  ------------------
  |  Branch (119:18): [True: 566k, False: 166k]
  ------------------
  120|   566k|        msg_id = kFilterStringField;
  121|   566k|      } else {  // FILTER_OPCODE_NESTED_FIELD
  122|       |        // The next word in the bytecode contains the message index.
  123|   166k|        if (!has_next_word) {
  ------------------
  |  Branch (123:13): [True: 12, False: 166k]
  ------------------
  124|     12|          PERFETTO_DLOG("bytecode error @ word %zu: unterminated nested field",
  125|     12|                        i);
  126|     12|          return false;
  127|     12|        }
  128|   166k|        msg_id = words[++i];
  129|   166k|        max_msg_index = std::max(max_msg_index, msg_id);
  130|   166k|      }
  131|       |
  132|  1.44M|      if (field_id < kDirectlyIndexLimit) {
  ------------------
  |  Branch (132:11): [True: 1.60k, False: 1.44M]
  ------------------
  133|  1.60k|        add_directly_indexed_field(field_id, msg_id);
  134|  1.44M|      } else {
  135|       |        // In the case of a large field id (rare) we waste an extra word and
  136|       |        // represent it as a range. Doesn't make sense to introduce extra
  137|       |        // complexity to deal with rare cases like this.
  138|  1.44M|        add_range(field_id, field_id + 1, msg_id);
  139|  1.44M|      }
  140|  9.28M|    } else if (opcode == kFilterOpcode_SimpleFieldRange) {
  ------------------
  |  Branch (140:16): [True: 1.25M, False: 8.03M]
  ------------------
  141|  1.25M|      if (!has_next_word) {
  ------------------
  |  Branch (141:11): [True: 37, False: 1.25M]
  ------------------
  142|     37|        PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
  143|     37|        return false;
  144|     37|      }
  145|  1.25M|      const uint32_t range_len = words[++i];
  146|  1.25M|      const uint32_t range_end = field_id + range_len;  // STL-style, excl.
  147|  1.25M|      uint32_t id = field_id;
  148|       |
  149|       |      // Here's the subtle complexity: at the bytecode level, we don't know
  150|       |      // anything about the kDirectlyIndexLimit. It is legit to define a range
  151|       |      // that spans across the direct-indexing threshold (e.g. 126-132). In that
  152|       |      // case we want to add all the elements < the indexing to the O(1) bucket
  153|       |      // and add only the remaining range as a non-indexed range.
  154|   135M|      for (; id < range_end && id < kDirectlyIndexLimit; ++id)
  ------------------
  |  Branch (154:14): [True: 135M, False: 53.8k]
  |  Branch (154:32): [True: 134M, False: 1.19M]
  ------------------
  155|   134M|        add_directly_indexed_field(id, kAllowed | kSimpleField);
  156|  1.25M|      PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
  157|  1.25M|      if (id < range_end)
  ------------------
  |  Branch (157:11): [True: 1.19M, False: 53.8k]
  ------------------
  158|  1.19M|        add_range(id, range_end, kSimpleField);
  159|  8.03M|    } else if (opcode == kFilterOpcode_EndOfMessage) {
  ------------------
  |  Branch (159:16): [True: 8.03M, False: 41]
  ------------------
  160|       |      // For each message append:
  161|       |      // 1. The "header" word telling how many directly indexed fields there
  162|       |      //    are.
  163|       |      // 2. The words for the directly indexed fields (id < 128).
  164|       |      // 3. The rest of the fields, encoded as ranges.
  165|       |      // Also update the |message_offset_| index to remember the word offset for
  166|       |      // the current message.
  167|  8.03M|      message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
  168|  8.03M|      words_.emplace_back(static_cast<uint32_t>(direct_indexed_fields.size()));
  169|  8.03M|      words_.insert(words_.end(), direct_indexed_fields.begin(),
  170|  8.03M|                    direct_indexed_fields.end());
  171|  8.03M|      words_.insert(words_.end(), ranges.begin(), ranges.end());
  172|  8.03M|      direct_indexed_fields.clear();
  173|  8.03M|      ranges.clear();
  174|  8.03M|    } else {
  175|     41|      PERFETTO_DLOG("bytecode error @ word %zu: invalid opcode (%x)", i, word);
  176|     41|      return false;
  177|     41|    }
  178|  10.7M|  }  // (for word in bytecode).
  179|       |
  180|    653|  if (!is_eom) {
  ------------------
  |  Branch (180:7): [True: 348, False: 305]
  ------------------
  181|    348|    PERFETTO_DLOG(
  182|    348|        "bytecode error: end of message not the last word in the bytecode");
  183|    348|    return false;
  184|    348|  }
  185|       |
  186|    305|  if (max_msg_index > 0 && max_msg_index >= message_offset_.size()) {
  ------------------
  |  Branch (186:7): [True: 164, False: 141]
  |  Branch (186:28): [True: 51, False: 113]
  ------------------
  187|     51|    PERFETTO_DLOG(
  188|     51|        "bytecode error: a message index (%u) is out of range "
  189|     51|        "(num_messages=%zu)",
  190|     51|        max_msg_index, message_offset_.size());
  191|     51|    return false;
  192|     51|  }
  193|       |
  194|       |  // Add a final entry to |message_offset_| so we can tell where the last
  195|       |  // message ends without an extra branch in the Query() hotpath.
  196|    254|  message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
  197|       |
  198|    254|  return true;
  199|    305|}
_ZNK9protozero20FilterBytecodeParser5QueryEjj:
  203|  24.3k|    uint32_t field_id) const {
  204|  24.3k|  FilterBytecodeParser::QueryResult res{false, 0u};
  205|  24.3k|  if (static_cast<uint64_t>(msg_index) + 1 >=
  ------------------
  |  Branch (205:7): [True: 18.2k, False: 6.11k]
  ------------------
  206|  24.3k|      static_cast<uint64_t>(message_offset_.size())) {
  207|  18.2k|    return res;
  208|  18.2k|  }
  209|  6.11k|  const uint32_t start_offset = message_offset_[msg_index];
  210|       |  // These are DCHECKs and not just CHECKS because the |words_| is populated
  211|       |  // by the LoadInternal call above. These cannot be violated with a malformed
  212|       |  // bytecode.
  213|  6.11k|  PERFETTO_DCHECK(start_offset < words_.size());
  214|  6.11k|  const uint32_t* word = &words_[start_offset];
  215|  6.11k|  const uint32_t end_off = message_offset_[msg_index + 1];
  216|  6.11k|  const uint32_t* const end = words_.data() + end_off;
  217|  6.11k|  PERFETTO_DCHECK(end > word && end <= words_.data() + words_.size());
  218|  6.11k|  const uint32_t num_directly_indexed = *(word++);
  219|  6.11k|  PERFETTO_DCHECK(num_directly_indexed <= kDirectlyIndexLimit);
  220|  6.11k|  PERFETTO_DCHECK(word + num_directly_indexed <= end);
  221|  6.11k|  uint32_t field_state = 0;
  222|  6.11k|  if (PERFETTO_LIKELY(field_id < num_directly_indexed)) {
  ------------------
  |  |   23|  6.11k|#define PERFETTO_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1)
  |  |  ------------------
  |  |  |  Branch (23:30): [True: 226, False: 5.89k]
  |  |  ------------------
  ------------------
  223|    226|    PERFETTO_DCHECK(&word[field_id] < end);
  224|    226|    field_state = word[field_id];
  225|  5.89k|  } else {
  226|  9.28k|    for (word = word + num_directly_indexed; word + 2 < end;) {
  ------------------
  |  Branch (226:46): [True: 3.44k, False: 5.84k]
  ------------------
  227|  3.44k|      const uint32_t range_start = *(word++);
  228|  3.44k|      const uint32_t range_end = *(word++);
  229|  3.44k|      const uint32_t range_state = *(word++);
  230|  3.44k|      if (field_id >= range_start && field_id < range_end) {
  ------------------
  |  Branch (230:11): [True: 2.46k, False: 985]
  |  Branch (230:38): [True: 50, False: 2.41k]
  ------------------
  231|     50|        field_state = range_state;
  232|     50|        break;
  233|     50|      }
  234|  3.44k|    }  // for (word in ranges)
  235|  5.89k|  }    // if (field_id >= num_directly_indexed)
  236|       |
  237|  6.11k|  res.allowed = (field_state & kAllowed) != 0;
  238|  6.11k|  res.nested_msg_index = field_state & ~kAllowed;
  239|  6.11k|  PERFETTO_DCHECK(!res.nested_msg_field() ||
  240|  6.11k|                  res.nested_msg_index < message_offset_.size() - 1);
  241|  6.11k|  return res;
  242|  24.3k|}
filter_bytecode_parser.cc:_ZZN9protozero20FilterBytecodeParser12LoadInternalEPKhmENK3$_0clEjj:
   79|   134M|  auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
   80|   134M|    PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
   81|   134M|    direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
   82|   134M|                                          static_cast<size_t>(field_id) + 1));
   83|   134M|    direct_indexed_fields[field_id] = kAllowed | msg_id;
   84|   134M|  };
filter_bytecode_parser.cc:_ZZN9protozero20FilterBytecodeParser12LoadInternalEPKhmENK3$_1clEjjj:
   86|  2.64M|  auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
   87|  2.64M|    PERFETTO_DCHECK(id_end > id_start);
   88|  2.64M|    PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
   89|  2.64M|    ranges.emplace_back(id_start);
   90|  2.64M|    ranges.emplace_back(id_end);
   91|  2.64M|    ranges.emplace_back(kAllowed | msg_id);
   92|  2.64M|  };

_ZN9protozero20FilterBytecodeParser28set_suppress_logs_for_fuzzerEb:
   85|    881|  void set_suppress_logs_for_fuzzer(bool x) { suppress_logs_for_fuzzer_ = x; }

LLVMFuzzerTestOneInput:
   92|    881|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   93|    881|  return protozero::FuzzBytecodeParser(data, size);
   94|    881|}
filter_bytecode_parser_fuzzer.cc:_ZN9protozero12_GLOBAL__N_118FuzzBytecodeParserEPKhm:
   49|    881|int FuzzBytecodeParser(const uint8_t* data, size_t size) {
   50|    881|  FilterBytecodeParser parser;
   51|    881|  parser.set_suppress_logs_for_fuzzer(true);
   52|       |
   53|    881|  if (size > 4 && data[0] < 192) {
  ------------------
  |  Branch (53:7): [True: 817, False: 64]
  |  Branch (53:19): [True: 475, False: 342]
  ------------------
   54|       |    // 75% of the times use the LoadBytecodeWithChecksum() which helps the
   55|       |    // fuzzer passing the checksum verification.
   56|    475|    LoadBytecodeWithChecksum(&parser, data + 1, size - 1);
   57|    475|  } else {
   58|       |    // In the remaining 25%, pass completely arbitrary inputs.
   59|    406|    parser.Load(data, size);
   60|    406|  }
   61|       |
   62|       |  // Smoke testing with known problematic values
   63|  3.52k|  for (uint32_t msg_index = 0; msg_index < 3; ++msg_index) {
  ------------------
  |  Branch (63:32): [True: 2.64k, False: 881]
  ------------------
   64|  2.64k|    parser.Query(msg_index, 0);
   65|  2.64k|    parser.Query(msg_index, 1);
   66|  2.64k|    parser.Query(msg_index, 127);
   67|  2.64k|    parser.Query(msg_index, 128);
   68|  2.64k|    parser.Query(msg_index, 129);
   69|  2.64k|    parser.Query(msg_index, 65536);
   70|  2.64k|    parser.Query(msg_index, 65536);
   71|  2.64k|    parser.Query(msg_index, 1u << 28);
   72|  2.64k|    parser.Query(msg_index, 1u << 31);
   73|  2.64k|  }
   74|       |
   75|       |  // Query using the random data at the end of the random buffer.
   76|    881|  if (size > 8) {
  ------------------
  |  Branch (76:7): [True: 539, False: 342]
  ------------------
   77|    539|    uint32_t msg_index = 0;
   78|    539|    uint32_t field_id = 0;
   79|    539|    memcpy(&msg_index, &data[size - 8], 4);
   80|    539|    memcpy(&field_id, &data[size - 4], 4);
   81|    539|    parser.Query(msg_index, field_id);
   82|    539|  }
   83|       |
   84|    881|  return 0;
   85|    881|}
filter_bytecode_parser_fuzzer.cc:_ZN9protozero12_GLOBAL__N_124LoadBytecodeWithChecksumEPNS_20FilterBytecodeParserEPKhm:
   36|    475|                              size_t size) {
   37|    475|  protozero::PackedVarInt words;
   38|    475|  perfetto::base::Hasher hasher;
   39|  3.56M|  for (size_t i = 0; i < size; i += sizeof(uint32_t)) {
  ------------------
  |  Branch (39:22): [True: 3.55M, False: 475]
  ------------------
   40|  3.55M|    uint32_t word = 0;
   41|  3.55M|    memcpy(&word, data, sizeof(uint32_t));
   42|  3.55M|    words.Append(word);
   43|  3.55M|    hasher.Update(word);
   44|  3.55M|  }
   45|    475|  words.Append(static_cast<uint32_t>(hasher.digest()));
   46|    475|  parser->Load(words.data(), words.size());
   47|    475|}

_ZN9protozero16PackedBufferBase12GrowSlowpathEv:
   23|    242|void PackedBufferBase::GrowSlowpath() {
   24|    242|  size_t write_off = static_cast<size_t>(write_ptr_ - storage_begin_);
   25|    242|  size_t old_size = static_cast<size_t>(storage_end_ - storage_begin_);
   26|    242|  size_t new_size = old_size < 65536 ? (old_size * 2) : (old_size * 3 / 2);
  ------------------
  |  Branch (26:21): [True: 119, False: 123]
  ------------------
   27|    242|  new_size = perfetto::base::AlignUp<4096>(new_size);
   28|    242|  std::unique_ptr<uint8_t[]> new_buf(new uint8_t[new_size]);
   29|    242|  memcpy(new_buf.get(), storage_begin_, old_size);
   30|    242|  heap_buf_ = std::move(new_buf);
   31|    242|  storage_begin_ = heap_buf_.get();
   32|    242|  storage_end_ = storage_begin_ + new_size;
   33|    242|  write_ptr_ = storage_begin_ + write_off;
   34|    242|}
_ZN9protozero16PackedBufferBase5ResetEv:
   36|    475|void PackedBufferBase::Reset() {
   37|    475|  heap_buf_.reset();
   38|    475|  storage_begin_ = reinterpret_cast<uint8_t*>(&stack_buf_[0]);
   39|    475|  storage_end_ = reinterpret_cast<uint8_t*>(&stack_buf_[kOnStackStorageSize]);
   40|    475|  write_ptr_ = storage_begin_;
   41|    475|}

