diff --git a/core/src/main/jni/src/elf_util.cpp b/core/src/main/jni/src/elf_util.cpp index 85f0c6cdf..fb6d2759b 100644 --- a/core/src/main/jni/src/elf_util.cpp +++ b/core/src/main/jni/src/elf_util.cpp @@ -27,6 +27,9 @@ #include #include +#include +#include +#include #include "linux/xz.h" #include "logging.h" @@ -373,47 +376,95 @@ constexpr inline bool contains(std::string_view a, std::string_view b) { return a.find(b) != std::string_view::npos; } +// A clean and simple struct to hold parsed map entry data. +struct MapEntry { + uintptr_t start_addr; + char perms[5] = {0}; // Assured null-termination + std::string pathname; +}; + bool ElfImg::findModuleBase() { - off_t load_addr; - bool found = false; + // Open the maps file using standard C file I/O. FILE *maps = fopen("/proc/self/maps", "r"); + if (!maps) { + LOGE("failed to open /proc/self/maps"); + return false; + } - char *buff = nullptr; - size_t len = 0; - ssize_t nread; - - while ((nread = getline(&buff, &len, maps)) != -1) { - std::string_view line{buff, static_cast(nread)}; - - if ((contains(line, "r-xp") || contains(line, "r--p")) && contains(line, elf)) { - LOGD("found: {}", line); - if (auto begin = line.find_last_of(' '); - begin != std::string_view::npos && line[++begin] == '/') { - found = true; - elf = line.substr(begin); - if (elf.back() == '\n') elf.pop_back(); - LOGD("update path: {}", elf); - break; - } + char line_buffer[512]; // A reasonable fixed-size buffer for map lines. + std::vector filtered_list; + + // Step 1: Filter all entries containing `elf` in its path. + while (fgets(line_buffer, sizeof(line_buffer), maps)) { + // Use an intermediate variable of a known, large type to avoid format warnings. + // `unsigned long long` and `%llx` are standard and portable. + unsigned long long temp_start; + char path_buffer[256] = {0}; + char p[5] = {0}; + + // Use the portable `%llx` specifier. + int items_parsed = + sscanf(line_buffer, "%llx-%*x %4s %*x %*s %*d %255s", &temp_start, p, path_buffer); + + // The filter condition: must parse the path, and it must contain the elf name. + if (items_parsed == 3 && strstr(path_buffer, elf.c_str()) != nullptr) { + MapEntry entry; + // Safely assign the parsed value to the uintptr_t. + entry.start_addr = static_cast(temp_start); + strncpy(entry.perms, p, 4); + entry.pathname = path_buffer; + filtered_list.push_back(std::move(entry)); } } - if (!found) { - if (buff) free(buff); - LOGE("failed to read load address for {}", elf); - fclose(maps); + fclose(maps); + + if (filtered_list.empty()) { + LOGE("Could not find any mappings for {}", elf.data()); return false; } - if (char *next = buff; load_addr = strtoul(buff, &next, 16), next == buff) { - LOGE("failed to read load address for {}", elf); + // Also part of Step 1: Print the filtered list for debugging. + LOGD("Found {} filtered map entries for {}:", filtered_list.size(), elf.data()); + for (const auto &entry : filtered_list) { + LOGD(" {:#x} {} {}", entry.start_addr, entry.perms, entry.pathname); } - if (buff) free(buff); + const MapEntry *found_block = nullptr; - fclose(maps); + // Step 2: In the filtered list, search for the first `r--p` whose next entry is `r-xp`. + for (size_t i = 0; i < filtered_list.size() - 1; ++i) { + if (strcmp(filtered_list[i].perms, "r--p") == 0 && + strcmp(filtered_list[i + 1].perms, "r-xp") == 0) { + found_block = &filtered_list[i]; + LOGD("Found `r--p` -> `r-xp` pattern. Choosing base from `r--p` block at {:#x}", + found_block->start_addr); + break; // Pattern found, exit loop. + } + } + + // Step 2 (Fallback): If the pattern was not found, find the first `r-xp` entry. + if (!found_block) { + LOGD("`r--p` -> `r-xp` pattern not found. Falling back to first `r-xp` entry."); + for (const auto &entry : filtered_list) { + if (strcmp(entry.perms, "r-xp") == 0) { + found_block = &entry; + LOGD("Found first `r-xp` block at {:#x}", found_block->start_addr); + break; // Fallback found, exit loop. + } + } + } + + if (!found_block) { + LOGE("Fatal: Could not determine a base address for {}", elf.data()); + return false; + } + + // Step 3: Use the starting address of the found block as the base address. + base = reinterpret_cast(found_block->start_addr); + elf = found_block->pathname; // Update elf path to the canonical one. - LOGD("get module base {}: {:#x}", elf, load_addr); + LOGD("get module base {}: {:#x}", elf, found_block->start_addr); + LOGD("update path: {}", elf); - base = reinterpret_cast(load_addr); return true; } diff --git a/external/lsplant b/external/lsplant index 4e9ad800e..a0990196c 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit 4e9ad800eba97550a38a1b4f9d06e4c3386aaf1c +Subproject commit a0990196c26e3fad57213a03af22dbf993396c8a