bool DwarfImpl::isAddrInRangeList()

in folly/experimental/symbolizer/DwarfImpl.cpp [373:497]


bool DwarfImpl::isAddrInRangeList(
    uint64_t address,
    folly::Optional<uint64_t> baseAddr,
    size_t offset,
    uint8_t addrSize) const {
  FOLLY_SAFE_CHECK(
      addrSize == 4 || addrSize == 8, "wrong address size: ", int(addrSize));
  if (cu_.version <= 4 && !cu_.debugSections.debugRanges.empty()) {
    const bool is64BitAddr = addrSize == 8;
    folly::StringPiece sp = cu_.debugSections.debugRanges;
    sp.advance(offset);
    const uint64_t maxAddr = is64BitAddr ? std::numeric_limits<uint64_t>::max()
                                         : std::numeric_limits<uint32_t>::max();
    while (!sp.empty()) {
      uint64_t begin = readOffset(sp, is64BitAddr);
      uint64_t end = readOffset(sp, is64BitAddr);
      // The range list entry is a base address selection entry.
      if (begin == maxAddr) {
        baseAddr = end;
        continue;
      }
      // The range list entry is an end of list entry.
      if (begin == 0 && end == 0) {
        break;
      }

      // Check if the given address falls in the range list entry.
      // 2.17.3 Non-Contiguous Address Ranges
      // The applicable base address of a range list entry is determined by the
      // closest preceding base address selection entry (see below) in the same
      // range list. If there is no such selection entry, then the applicable
      // base address defaults to the base address of the compilation unit.
      if (baseAddr && address >= begin + *baseAddr &&
          address < end + *baseAddr) {
        return true;
      }
    };
  }

  if (cu_.version == 5 && !cu_.debugSections.debugRnglists.empty() &&
      cu_.addrBase.has_value()) {
    auto debugRnglists = cu_.debugSections.debugRnglists;
    debugRnglists.advance(offset);

    while (!debugRnglists.empty()) {
      auto kind = read<uint8_t>(debugRnglists);
      switch (kind) {
        case DW_RLE_end_of_list:
          return false;
        case DW_RLE_base_addressx: {
          auto index = readULEB(debugRnglists);
          auto sp = cu_.debugSections.debugAddr.subpiece(
              *cu_.addrBase + index * sizeof(uint64_t));
          baseAddr = read<uint64_t>(sp);
        } break;

        case DW_RLE_startx_endx: {
          auto indexStart = readULEB(debugRnglists);
          auto indexEnd = readULEB(debugRnglists);
          auto spStart = cu_.debugSections.debugAddr.subpiece(
              *cu_.addrBase + indexStart * sizeof(uint64_t));
          auto start = read<uint64_t>(spStart);

          auto spEnd = cu_.debugSections.debugAddr.subpiece(
              *cu_.addrBase + indexEnd * sizeof(uint64_t));
          auto end = read<uint64_t>(spEnd);
          if (address >= start && address < end) {
            return true;
          }
        } break;

        case DW_RLE_startx_length: {
          auto indexStart = readULEB(debugRnglists);
          auto length = readULEB(debugRnglists);
          auto spStart = cu_.debugSections.debugAddr.subpiece(
              *cu_.addrBase + indexStart * sizeof(uint64_t));
          auto start = read<uint64_t>(spStart);

          auto spEnd = cu_.debugSections.debugAddr.subpiece(
              *cu_.addrBase + indexStart * sizeof(uint64_t) + length);
          auto end = read<uint64_t>(spEnd);
          if (start != end && address >= start && address < end) {
            return true;
          }
        } break;

        case DW_RLE_offset_pair: {
          auto offsetStart = readULEB(debugRnglists);
          auto offsetEnd = readULEB(debugRnglists);
          if (baseAddr && address >= (*baseAddr + offsetStart) &&
              address < (*baseAddr + offsetEnd)) {
            return true;
          }
        } break;

        case DW_RLE_base_address:
          baseAddr = read<uint64_t>(debugRnglists);
          break;

        case DW_RLE_start_end: {
          uint64_t start = read<uint64_t>(debugRnglists);
          uint64_t end = read<uint64_t>(debugRnglists);
          if (address >= start && address < end) {
            return true;
          }
        } break;

        case DW_RLE_start_length: {
          uint64_t start = read<uint64_t>(debugRnglists);
          uint64_t end = start + readULEB(debugRnglists);
          if (address >= start && address < end) {
            return true;
          }
        } break;

        default:
          FOLLY_SAFE_CHECK(
              false,
              "Unexpected debug_rnglists entry kind: ",
              static_cast<int>(kind));
      }
    }
  }
  return false;
}