LIEF::Binary::functions_t Binary::unwind_functions() const {
  static constexpr size_t UNWIND_COMPRESSED = 3;
  static constexpr size_t UNWIND_UNCOMPRESSED = 2;

  // Set container to have functions with unique address
  static const auto fcmd = [] (const Function& l, const Function& r) {
    return l.address() < r.address();
  };
  std::set<Function, decltype(fcmd)> functions(fcmd);

  // Look for the __unwind_info section
  const Section* unwind_section = get_section("__unwind_info");
  if (unwind_section == nullptr) {
    return {};
  }

  SpanStream vs = unwind_section->content();

  // Get section content
  const auto hdr = vs.read<details::unwind_info_section_header>();
  if (!hdr) {
    LIEF_ERR("Can't read unwind section header!");
    return {};
  }
  vs.setpos(hdr->index_section_offset);

  size_t lsda_start = -1lu;
  size_t lsda_stop = 0;
  for (size_t i = 0; i < hdr->index_count; ++i) {
    const auto section_hdr = vs.read<details::unwind_info_section_header_index_entry>();
    if (!section_hdr) {
      LIEF_ERR("Can't read function information at index #{:d}", i);
      break;
    }

    functions.emplace(section_hdr->function_offset);
    const size_t second_lvl_off = section_hdr->second_level_pages_section_offset;
    const size_t lsda_off       = section_hdr->lsda_index_array_section_offset;

    lsda_start = std::min(lsda_off, lsda_start);
    lsda_stop  = std::max(lsda_off, lsda_stop);

    if (second_lvl_off > 0 && vs.can_read<details::unwind_info_regular_second_level_page_header>(second_lvl_off)) {
      const size_t saved_pos = vs.pos();
      {
        vs.setpos(second_lvl_off);
        const auto lvl_hdr = vs.peek<details::unwind_info_regular_second_level_page_header>(second_lvl_off);
        if (!lvl_hdr) {
          break;
        }
        if (lvl_hdr->kind == UNWIND_COMPRESSED) {
          const auto lvl_compressed_hdr = vs.read<details::unwind_info_compressed_second_level_page_header>();
          if (!lvl_compressed_hdr) {
            LIEF_ERR("Can't read lvl_compressed_hdr");
            break;
          }

          vs.setpos(second_lvl_off + lvl_compressed_hdr->entry_page_offset);
          for (size_t j = 0; j < lvl_compressed_hdr->entry_count; ++j) {
            auto entry = vs.read<uint32_t>();
            if (!entry) {
              break;
            }
            uint32_t func_off = section_hdr->function_offset + (*entry & 0xffffff);
            functions.emplace(func_off);
          }
        }
        else if (lvl_hdr->kind == UNWIND_UNCOMPRESSED) {
          LIEF_WARN("UNWIND_UNCOMPRESSED is not supported yet!");
        }
        else {
          LIEF_WARN("Unknown 2nd level kind: {:d}", lvl_hdr->kind);
        }
      }
      vs.setpos(saved_pos);
    }

  }

  const size_t nb_lsda = lsda_stop > lsda_start ? (lsda_stop - lsda_start) / sizeof(details::unwind_info_section_header_lsda_index_entry) : 0;
  vs.setpos(lsda_start);
  for (size_t i = 0; i < nb_lsda; ++i) {
    const auto hdr = vs.read<details::unwind_info_section_header_lsda_index_entry>();
    if (!hdr) {
      LIEF_ERR("Can't read LSDA at index #{:d}", i);
      break;
    }
    functions.emplace(hdr->function_offset);
  }

  return {std::begin(functions), std::end(functions)};
}
LIEF::Binary::functions_t Binary::unwind_functions() const {
  static constexpr size_t UNWIND_COMPRESSED = 3;
  static constexpr size_t UNWIND_UNCOMPRESSED = 2;

   
  static const auto fcmd = [] (const Function& l, const Function& r) {
    return l.address() < r.address();
  };
  std::set<Function, decltype(fcmd)> functions(fcmd);

   
  const Section* unwind_section = get_section("__unwind_info");
  if (unwind_section == nullptr) {
    return {};
  }

  SpanStream vs = unwind_section->content();

   
  const auto hdr = vs.read<details::unwind_info_section_header>();
  if (!hdr) {
    LIEF_ERR("Can't read unwind section header!");
    return {};
  }
  vs.setpos(hdr->index_section_offset);

  size_t lsda_start = -1lu;
  size_t lsda_stop = 0;
  for (size_t i = 0; i < hdr->index_count; ++i) {
    const auto section_hdr = vs.read<details::unwind_info_section_header_index_entry>();
    if (!section_hdr) {
      LIEF_ERR("Can't read function information at index #{:d}", i);
      break;
    }

    functions.emplace(section_hdr->function_offset);
    const size_t second_lvl_off = section_hdr->second_level_pages_section_offset;
    const size_t lsda_off       = section_hdr->lsda_index_array_section_offset;

    lsda_start = std::min(lsda_off, lsda_start);
    lsda_stop  = std::max(lsda_off, lsda_stop);

    if (second_lvl_off > 0 && vs.can_read<details::unwind_info_regular_second_level_page_header>(second_lvl_off)) {
      const size_t saved_pos = vs.pos();
      {
        vs.setpos(second_lvl_off);
        const auto lvl_hdr = vs.peek<details::unwind_info_regular_second_level_page_header>(second_lvl_off);
        if (!lvl_hdr) {
          break;
        }
        if (lvl_hdr->kind == UNWIND_COMPRESSED) {
          const auto lvl_compressed_hdr = vs.read<details::unwind_info_compressed_second_level_page_header>();
          if (!lvl_compressed_hdr) {
            LIEF_ERR("Can't read lvl_compressed_hdr");
            break;
          }

          vs.setpos(second_lvl_off + lvl_compressed_hdr->entry_page_offset);
          for (size_t j = 0; j < lvl_compressed_hdr->entry_count; ++j) {
            auto entry = vs.read<uint32_t>();
            if (!entry) {
              break;
            }
            uint32_t func_off = section_hdr->function_offset + (*entry & 0xffffff);
            functions.emplace(func_off);
          }
        }
        else if (lvl_hdr->kind == UNWIND_UNCOMPRESSED) {
          LIEF_WARN("UNWIND_UNCOMPRESSED is not supported yet!");
        }
        else {
          LIEF_WARN("Unknown 2nd level kind: {:d}", lvl_hdr->kind);
        }
      }
      vs.setpos(saved_pos);
    }

  }

  const size_t nb_lsda = lsda_stop > lsda_start ? (lsda_stop - lsda_start) / sizeof(details::unwind_info_section_header_lsda_index_entry) : 0;
  vs.setpos(lsda_start);
  for (size_t i = 0; i < nb_lsda; ++i) {
    const auto hdr = vs.read<details::unwind_info_section_header_lsda_index_entry>();
    if (!hdr) {
      LIEF_ERR("Can't read LSDA at index #{:d}", i);
      break;
    }
    functions.emplace(hdr->function_offset);
  }

  return {std::begin(functions), std::end(functions)};
}