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();
}