+/***********************************************************************
+ * objc::SafeRanges::find. Find an image data segment that contains address
+ **********************************************************************/
+bool
+objc::SafeRanges::find(uintptr_t ptr, uint32_t &pos)
+{
+ if (!sorted) {
+ std::sort(ranges, ranges + count, [](const Range &s1, const Range &s2){
+ return s1.start < s2.start;
+ });
+ sorted = true;
+ }
+
+ uint32_t l = 0, r = count;
+ while (l < r) {
+ uint32_t i = (l + r) / 2;
+
+ if (ptr < ranges[i].start) {
+ r = i;
+ } else if (ptr >= ranges[i].end) {
+ l = i + 1;
+ } else {
+ pos = i;
+ return true;
+ }
+ }
+
+ pos = UINT32_MAX;
+ return false;
+}
+
+/***********************************************************************
+ * objc::SafeRanges::add. Register a new well known data segment.
+ **********************************************************************/
+void
+objc::SafeRanges::add(uintptr_t start, uintptr_t end)
+{
+ if (count == size) {
+ // Have a typical malloc growth:
+ // - size <= 32: grow by 4
+ // - size <= 64: grow by 8
+ // - size <= 128: grow by 16
+ // ... etc
+ size += size < 16 ? 4 : 1 << (fls(size) - 3);
+ ranges = (Range *)realloc(ranges, sizeof(Range) * size);
+ }
+ ranges[count++] = Range{ start, end };
+ sorted = false;
+}
+
+/***********************************************************************
+ * objc::SafeRanges::remove. Remove a previously known data segment.
+ **********************************************************************/
+void
+objc::SafeRanges::remove(uintptr_t start, uintptr_t end)
+{
+ uint32_t pos;
+
+ if (!find(start, pos) || ranges[pos].end != end) {
+ _objc_fatal("Cannot find range %#lx..%#lx", start, end);
+ }
+ if (pos < --count) {
+ ranges[pos] = ranges[count];
+ sorted = false;
+ }
+}