Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: find .text section using dl_iterate_phdr #32244

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
120 changes: 57 additions & 63 deletions src/large_pages/node_large_page.cc
Expand Up @@ -29,7 +29,12 @@
#include "util.h"
#include "uv.h"

#include <fcntl.h> // _O_RDWR
#if defined(__linux__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <link.h>
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
#endif
#include <sys/types.h>
#include <sys/mman.h>
#if defined(__FreeBSD__)
Expand All @@ -38,19 +43,17 @@
#elif defined(__APPLE__)
#include <mach/vm_map.h>
#endif
#include <unistd.h> // readlink
#include <unistd.h> // getpid

#include <climits> // PATH_MAX
#include <clocale>
#include <csignal>
#include <cstdio>
gabrielschulhof marked this conversation as resolved.
Show resolved Hide resolved
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>

// The functions in this file map the text segment of node into 2M pages.
Expand Down Expand Up @@ -110,72 +113,63 @@ inline uintptr_t hugepage_align_down(uintptr_t addr) {
return ((addr) & ~((hps) - 1));
}

// The format of the maps file is the following
// address perms offset dev inode pathname
// 00400000-00452000 r-xp 00000000 08:02 173521 /usr/bin/dbus-daemon
// This is also handling the case where the first line is not the binary.
struct dl_iterate_params {
uintptr_t start;
uintptr_t end;
uintptr_t reference_sym;
};

#if defined(__linux__)
int FindMapping(struct dl_phdr_info* info, size_t, void* data) {
if (info->dlpi_name[0] == 0) {
for (int idx = 0; idx < info->dlpi_phnum; idx++) {
const ElfW(Phdr)* phdr = &info->dlpi_phdr[idx];
if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X)) {
auto dl_params = static_cast<dl_iterate_params*>(data);
uintptr_t start = info->dlpi_addr + phdr->p_vaddr;
uintptr_t end = start + phdr->p_memsz;

if (dl_params->reference_sym >= start &&
dl_params->reference_sym <= end) {
dl_params->start = start;
dl_params->end = end;
return 1;
}
}
}
}
return 0;
}
#endif // defined(__linux__)

struct text_region FindNodeTextRegion() {
struct text_region nregion;
nregion.found_text_region = false;
#if defined(__linux__)
std::ifstream ifs;
std::string map_line;
std::string permission;
std::string dev;
char dash;
uintptr_t start, end, offset, inode;
uintptr_t node_text_start = reinterpret_cast<uintptr_t>(&__node_text_start);
dl_iterate_params dl_params = {
0, 0, reinterpret_cast<uintptr_t>(&__node_text_start)
};
uintptr_t lpstub_start = reinterpret_cast<uintptr_t>(&__start_lpstub);

ifs.open("/proc/self/maps");
if (!ifs) {
PrintWarning("could not open /proc/self/maps");
return nregion;
}

while (std::getline(ifs, map_line)) {
std::istringstream iss(map_line);
iss >> std::hex >> start;
iss >> dash;
iss >> std::hex >> end;
iss >> permission;
iss >> offset;
iss >> dev;
iss >> inode;

if (inode == 0)
continue;

std::string pathname;
iss >> pathname;

if (permission != "r-xp")
continue;

if (node_text_start < start || node_text_start >= end)
continue;

start = node_text_start;
if (lpstub_start > start && lpstub_start <= end)
end = lpstub_start;

char* from = reinterpret_cast<char*>(hugepage_align_up(start));
char* to = reinterpret_cast<char*>(hugepage_align_down(end));

if (from >= to)
break;

size_t size = to - from;
nregion.found_text_region = true;
nregion.from = from;
nregion.to = to;
nregion.total_hugepages = size / hps;

break;
if (dl_iterate_phdr(FindMapping, &dl_params) == 1) {
dl_params.start = dl_params.reference_sym;
if (lpstub_start > dl_params.start && lpstub_start <= dl_params.end)
dl_params.end = lpstub_start;

if (dl_params.start < dl_params.end) {
char* from = reinterpret_cast<char*>(hugepage_align_up(dl_params.start));
char* to = reinterpret_cast<char*>(hugepage_align_down(dl_params.end));
if (from < to) {
size_t pagecount = (to - from) / hps;
if (pagecount > 0) {
nregion.found_text_region = true;
nregion.from = from;
nregion.to = to;
nregion.total_hugepages = pagecount;
}
}
}
Comment on lines +159 to +171
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnoordhuis I added some more sanity checks to ensure that we create a region that has proper offsets and > 0 page count.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... or rather, that we consider the region to have been found only if it has proper offsets and >0 page count.

}

ifs.close();
#elif defined(__FreeBSD__)
std::string exename;
{
Expand Down Expand Up @@ -289,7 +283,7 @@ bool IsTransparentHugePagesEnabled() {
return always == "[always]" || madvise == "[madvise]";
}
#elif defined(__FreeBSD__)
static bool IsSuperPagesEnabled() {
bool IsSuperPagesEnabled() {
// It is enabled by default on amd64.
unsigned int super_pages = 0;
size_t super_pages_length = sizeof(super_pages);
Expand Down