From 48eead4cbb711cf1c522fdc7b421bf3aa798deee Mon Sep 17 00:00:00 2001 From: Eugene Tarassov Date: Sat, 29 Sep 2018 10:09:02 -0700 Subject: TCF Agent: fixed handling of overlapping memory map regions on Linux --- agent/system/GNU/Linux/tcf/context-linux.c | 69 ++++++++++++++++++++---------- agent/tcf/services/tcf_elf.c | 25 +++++++++++ 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/agent/system/GNU/Linux/tcf/context-linux.c b/agent/system/GNU/Linux/tcf/context-linux.c index 06224b17..ea518f82 100644 --- a/agent/system/GNU/Linux/tcf/context-linux.c +++ b/agent/system/GNU/Linux/tcf/context-linux.c @@ -1036,7 +1036,7 @@ int context_get_memory_map(Context * ctx, MemoryMap * map) { &addr0, &addr1, permissions, &offset, &dev_ma, &dev_mi, &inode); if (cnt == 0 || cnt == EOF) break; - for (;;) { + for (i = 0;;) { int ch = fgetc(file); if (ch == '\n' || ch == EOF) break; if (i < FILE_PATH_SIZE - 1 && (ch != ' ' || i > 0)) { @@ -1062,27 +1062,52 @@ int context_get_memory_map(Context * ctx, MemoryMap * map) { if (map->region_cnt > 0) prev = map->regions + (map->region_cnt - 1); if (inode != 0 && file_name[0] && file_name[0] != '[') { - MemoryRegion * r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->addr = addr0; - r->size = addr1 - addr0; - r->flags = flags; - r->file_offs = offset; - r->dev = MKDEV(dev_ma, dev_mi); - r->ino = (ino_t)inode; - r->file_name = loc_strdup(file_name); - } - else if (file_name[0] == 0 && prev != NULL && prev->addr + prev->size == addr0) { - MemoryRegion * r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->bss = 1; - r->addr = addr0; - r->size = addr1 - addr0; - r->flags = flags; - r->file_offs = prev->file_offs + prev->size; - r->dev = prev->dev; - r->ino = prev->ino; - r->file_name = loc_strdup(prev->file_name); + if (prev != NULL && (prev->flags & MM_FLAG_X) == 0 && + prev->file_size == prev->size && prev->dev == MKDEV(dev_ma, dev_mi) && prev->ino == (ino_t)inode && + prev->file_offs + prev->file_size == offset && prev->addr + prev->size == addr0) { + prev->file_size += addr1 - addr0; + prev->size += addr1 - addr0; + prev->flags |= flags; + } + else { + MemoryRegion * r = map->regions + map->region_cnt++; + memset(r, 0, sizeof(MemoryRegion)); + r->addr = addr0; + r->valid |= MM_VALID_ADDR; + r->size = addr1 - addr0; + r->valid |= MM_VALID_SIZE; + r->flags = flags; + r->file_offs = offset; + r->valid |= MM_VALID_FILE_OFFS; + r->file_size = addr1 - addr0; + r->valid |= MM_VALID_FILE_SIZE; + r->dev = MKDEV(dev_ma, dev_mi); + r->ino = (ino_t)inode; + r->file_name = loc_strdup(file_name); + } + } + else if ((file_name[0] == 0 || strcmp(file_name, "[heap]") == 0) && + prev != NULL && prev->addr + prev->size == addr0) { + if ((prev->flags & MM_FLAG_X) == 0) { + prev->size += addr1 - addr0; + prev->flags |= flags; + } + else { + MemoryRegion * r = map->regions + map->region_cnt++; + memset(r, 0, sizeof(MemoryRegion)); + r->bss = 1; + r->addr = addr0; + r->valid |= MM_VALID_ADDR; + r->size = addr1 - addr0; + r->valid |= MM_VALID_SIZE; + r->flags = flags; + r->file_offs = prev->file_offs + prev->size; + r->valid |= MM_VALID_FILE_OFFS; + r->valid |= MM_VALID_FILE_SIZE; + r->dev = prev->dev; + r->ino = prev->ino; + r->file_name = loc_strdup(prev->file_name); + } } } fclose(file); diff --git a/agent/tcf/services/tcf_elf.c b/agent/tcf/services/tcf_elf.c index c1ffeb0e..6e1ac357 100644 --- a/agent/tcf/services/tcf_elf.c +++ b/agent/tcf/services/tcf_elf.c @@ -1507,6 +1507,7 @@ static void search_regions(MemoryMap * map, ContextAddress addr0, ContextAddress } int elf_get_map(Context * ctx, ContextAddress addr0, ContextAddress addr1, MemoryMap * map) { + unsigned i; map->region_cnt = 0; ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS); #if ENABLE_MemoryMap @@ -1532,6 +1533,30 @@ int elf_get_map(Context * ctx, ContextAddress addr0, ContextAddress addr1, Memor } } #endif + for (i = 0; i + 1 < map->region_cnt; i++) { + MemoryRegion * m = map->regions + i; + MemoryRegion * r = m + 1; + if (m->file_size == m->size && m->file_offs < r->file_offs && m->file_offs + m->file_size > r->file_offs && + m->file_name != NULL && r->file_name != NULL && strcmp(m->file_name, r->file_name) == 0) { + /* Ambiguity: overlapping regions */ + ELF_File * elf = elf_open(r->file_name); + for (i = 0; i < elf->pheader_cnt; i++) { + ELF_PHeader * p = elf->pheaders + i; + if (p->type == PT_LOAD && p->offset == m->file_offs && p->mem_size < m->size) { + m->file_size = p->mem_size; + m->size = p->mem_size; + if (m->file_offs + m->size > r->file_offs && p->mem_size == p->file_size) { + uint64_t diff = m->file_offs + m->file_size - r->file_offs; + r->file_offs += diff; + r->file_size -= diff; + r->addr += diff; + r->size -= diff; + } + break; + } + } + } + } return 0; } -- cgit v1.2.3