Bug 511631 - address_to_line does not find all CodeAreas
diff --git a/agent/tcf/services/dwarfframe.c b/agent/tcf/services/dwarfframe.c
index 416f329..8b80820 100644
--- a/agent/tcf/services/dwarfframe.c
+++ b/agent/tcf/services/dwarfframe.c
@@ -1303,6 +1303,10 @@
         else if (range->mAddr > IP) {
             h = k;
         }
+        else if (range->mAddr + range->mSize < range->mAddr) {
+            read_frame_fde(IP, range->mOffset);
+            return;
+        }
         else if (range->mAddr + range->mSize <= IP) {
             l = k + 1;
         }
diff --git a/agent/tcf/services/linenumbers_elf.c b/agent/tcf/services/linenumbers_elf.c
index e51e69f..b325815 100644
--- a/agent/tcf/services/linenumbers_elf.c
+++ b/agent/tcf/services/linenumbers_elf.c
@@ -352,22 +352,33 @@
 int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, LineNumbersCallBack * client, void * args) {
     Trap trap;
 
+    /* TODO: make addr0..addr1 range inclusive */
+    if (addr1 == 0) return 0;
+    addr1--;
+
     if (!set_trap(&trap)) return -1;
     if (ctx == NULL) exception(ERR_INV_CONTEXT);
     if (ctx->exited) exception(ERR_ALREADY_EXITED);
-    while (addr0 < addr1) {
+    while (addr0 <= addr1) {
         ContextAddress range_rt_addr = 0;
-        UnitAddressRange * range = elf_find_unit(ctx, addr0, addr1 - 1, &range_rt_addr);
+        UnitAddressRange * range = elf_find_unit(ctx, addr0, addr1, &range_rt_addr);
         if (range == NULL) break;
+        assert(range->mSize > 0);
+        assert(range->mAddr + range->mSize > range->mAddr || range->mAddr + range->mSize == 0);
+        assert(range_rt_addr + range->mSize > range_rt_addr || range_rt_addr + range->mSize == 0);
+        assert(addr1 >= range_rt_addr);
+        assert(addr0 <= range_rt_addr + range->mSize - 1);
         if (!range->mUnit->mLineInfoLoaded) load_line_numbers(range->mUnit);
         if (range->mUnit->mStatesCnt >= 2) {
             CompUnit * unit = range->mUnit;
             unsigned l = 0;
             unsigned h = unit->mStatesCnt;
-            ContextAddress addr_min = addr0 - range_rt_addr + range->mAddr;
-            ContextAddress addr_max = addr1 - range_rt_addr + range->mAddr;
-            if (addr_min < range->mAddr) addr_min = range->mAddr;
-            if (addr_max > range->mAddr + range->mSize) addr_max = range->mAddr + range->mSize;
+            ContextAddress addr_min = range->mAddr;
+            ContextAddress addr_max = range->mAddr + range->mSize - 1;
+            if (addr0 > range_rt_addr) addr_min = addr0 - range_rt_addr + range->mAddr;
+            if (addr1 < range_rt_addr + range->mSize - 1) addr_max = addr1 - range_rt_addr + range->mAddr;
+            assert(addr_min >= range->mAddr);
+            assert(addr_max <= range->mAddr + range->mSize - 1);
             while (l < h) {
                 unsigned k = (h + l) / 2;
                 LineNumbersState * state = unit->mStates + k;
@@ -377,7 +388,7 @@
                 else if (state->mSection < range->mSection) {
                     l = k + 1;
                 }
-                else if (state->mAddress >= addr_max) {
+                else if (state->mAddress > addr_max) {
                     h = k;
                 }
                 else {
@@ -389,7 +400,7 @@
                         while (k > 0) {
                             LineNumbersState * prev = unit->mStates + k - 1;
                             if (state->mAddress <= addr_min) break;
-                            if (prev->mAddress >= addr_max) break;
+                            if (prev->mAddress > addr_max) break;
                             state = prev;
                             k--;
                         }
@@ -411,7 +422,7 @@
                             }
                             if (k >= unit->mStatesCnt) break;
                             state = unit->mStates + k;
-                            if (state->mAddress >= addr_max) break;
+                            if (state->mAddress > addr_max) break;
                         }
                         break;
                     }
diff --git a/agent/tcf/services/tcf_elf.c b/agent/tcf/services/tcf_elf.c
index 2d14e63..3b43dd4 100644
--- a/agent/tcf/services/tcf_elf.c
+++ b/agent/tcf/services/tcf_elf.c
@@ -1371,7 +1371,7 @@
                 }
             }
         }
-        else if (r->addr <= addr1 && r->addr + r->size > addr0) {
+        else if (r->size > 0 && r->addr <= addr1 && r->addr + r->size - 1 >= addr0) {
             *add_region(res) = *r;
         }
     }
@@ -1570,8 +1570,9 @@
         ContextAddress link_addr_min, link_addr_max;
         MemoryRegion * r = elf_map.regions + i;
         ELF_File * file = NULL;
+        assert(r->size > 0);
         assert(r->addr <= addr_max);
-        assert(r->addr + r->size > addr_min);
+        assert(r->addr + r->size - 1 >= addr_min);
         file = elf_open_memory_region_file(r, &error);
         if (file == NULL) {
             if (error) {
@@ -1582,24 +1583,29 @@
             continue;
         }
         if (r->sect_name == NULL) {
+            U8_T offs_min = r->file_offs;
+            U8_T offs_max = r->file_offs + r->size - 1;
             ELF_File * debug = get_dwarf_file(file);
+            if (addr_min > r->addr) offs_min = addr_min - r->addr + r->file_offs;
+            if (addr_max < r->addr + r->size - 1) offs_max = addr_max - r->addr + r->file_offs;
+            assert(offs_min <= offs_max);
+            assert(offs_max >= r->file_offs);
+            assert(offs_min <= r->file_offs + r->size - 1);
             for (j = 0; range == NULL && j < file->pheader_cnt; j++) {
-                U8_T offs_min = 0;
-                U8_T offs_max = 0;
                 U8_T pheader_address = 0;
                 U8_T pheader_file_size = 0;
                 ELF_PHeader * p = file->pheaders + j;
                 ELF_Section * sec = NULL;
+                if (p->offset > offs_max) continue;
                 if (!is_p_header_region(file, p, r)) continue;
                 pheader_address = get_debug_pheader_address(file, debug, p);
                 pheader_file_size = get_pheader_file_size(file, p, r);
-                offs_min = addr_min - r->addr + r->file_offs;
-                offs_max = addr_max - r->addr + r->file_offs;
-                if (p->offset > offs_max || p->offset + pheader_file_size <= offs_min) continue;
+                if (pheader_file_size == 0) continue;
+                if (p->offset + pheader_file_size <= offs_min) continue;
                 link_addr_min = (ContextAddress)(offs_min - p->offset + pheader_address);
                 link_addr_max = (ContextAddress)(offs_max - p->offset + pheader_address);
                 if (link_addr_min < pheader_address) link_addr_min = (ContextAddress)pheader_address;
-                if (link_addr_max >= pheader_address + pheader_file_size) link_addr_max = (ContextAddress)(pheader_address + pheader_file_size - 1);
+                if (link_addr_max > pheader_address + pheader_file_size - 1) link_addr_max = (ContextAddress)(pheader_address + pheader_file_size - 1);
                 if (!file->debug_info_file) sec = find_section_by_offset(file, offs_min);
                 range = find_comp_unit_addr_range(get_dwarf_cache(debug), sec, link_addr_min, link_addr_max);
                 if (range != NULL && range_rt_addr != NULL) {
@@ -1613,10 +1619,12 @@
             for (idx = 1; range == NULL && idx < debug->section_cnt; idx++) {
                 ELF_Section * sec = debug->sections + idx;
                 if (sec->name != NULL && strcmp(sec->name, r->sect_name) == 0) {
-                    link_addr_min = (ContextAddress)(addr_min - r->addr + sec->addr);
-                    link_addr_max = (ContextAddress)(addr_max - r->addr + sec->addr);
-                    if (link_addr_min < sec->addr) link_addr_min = (ContextAddress)sec->addr;
-                    if (link_addr_max >= sec->addr + sec->size) link_addr_max = (ContextAddress)(sec->addr + sec->size - 1);
+                    if (addr_min < r->addr) link_addr_min = sec->addr;
+                    else link_addr_min = (ContextAddress)(addr_min - r->addr + sec->addr);
+                    if (addr_max > r->addr + r->size - 1) link_addr_max = sec->addr + r->size - 1;
+                    else link_addr_max = (ContextAddress)(addr_max - r->addr + sec->addr);
+                    assert(link_addr_min >= sec->addr);
+                    assert(link_addr_max <= sec->addr + r->size - 1);
                     range = find_comp_unit_addr_range(get_dwarf_cache(debug), sec, link_addr_min, link_addr_max);
                     if (range != NULL && range_rt_addr != NULL) {
                         *range_rt_addr = (ContextAddress)(range->mAddr - sec->addr + r->addr);
@@ -1633,6 +1641,10 @@
     /* Note: when debug info is in a separate file, debug file link-time addresses are not same as exec file link-time addresses,
      * because Linux has a habbit of re-linking execs after extracting debug info */
     unsigned i;
+    if (r->size == 0) {
+        errno = ERR_INV_ADDRESS;
+        return 0;
+    }
     errno = 0;
     if (r->sect_name == NULL) {
         ContextAddress rt = 0;
@@ -1641,7 +1653,7 @@
             if (!is_p_header_region(file, p, r)) continue;
             if (addr < p->address || addr >= p->address + p->mem_size) continue;
             rt = (ContextAddress)(addr - p->address + p->offset - r->file_offs + r->addr);
-            if (rt < r->addr || rt >= r->addr + r->size) continue;
+            if (rt < r->addr || rt > r->addr + r->size - 1) continue;
             return rt;
         }
     }
@@ -1719,8 +1731,9 @@
         MemoryRegion * r = elf_map.regions + i;
         ELF_File * f = NULL;
         ELF_File * d = NULL;
+        assert(r->size > 0);
         assert(r->addr <= addr);
-        assert(r->addr + r->size > addr);
+        assert(r->addr + r->size - 1 >= addr);
         f = elf_open_memory_region_file(r, NULL);
         if (f == NULL) continue;
         d = to_dwarf ? get_dwarf_file(f) : f;
diff --git a/tests/test-dwarf/tcf/backend/backend.c b/tests/test-dwarf/tcf/backend/backend.c
index f59ed96..24fdfc3 100644
--- a/tests/test-dwarf/tcf/backend/backend.c
+++ b/tests/test-dwarf/tcf/backend/backend.c
@@ -1654,6 +1654,22 @@
     }
 }
 
+static void check_line_info_cb(CodeArea * area, void * args) {
+    area_cnt++;
+}
+
+static void check_line_info(void) {
+    assert(file_has_line_info);
+    area_cnt = 0;
+    if (address_to_line(elf_ctx, 0, 0xffffffffffffffff, check_line_info_cb, check_line_info_cb) < 0) {
+        error("address_to_line");
+    }
+    if (area_cnt == 0) {
+        set_errno(ERR_OTHER, "address_to_line(elf_ctx, 0, 0xffffffffffffffff,...) does not work");
+        error("address_to_line");
+    }
+}
+
 static void next_region(void) {
     Symbol * sym = NULL;
     ContextAddress lt_addr;
@@ -2271,9 +2287,12 @@
     assert(test_posted);
     test_posted = 0;
     if (elf_file_name == NULL || mem_region_pos >= (int)mem_map.region_cnt) {
-        if (file_has_line_info && line_info_cnt == 0) {
-            set_errno(ERR_OTHER, "Line info not accessable");
-            error("address_to_line");
+        if (file_has_line_info) {
+            if (line_info_cnt == 0) {
+                set_errno(ERR_OTHER, "Line info not accessable");
+                error("address_to_line");
+            }
+            check_line_info();
         }
         next_file();
     }