#include <sys/types.h>
#include <sys/wait.h>
+#define min(a, b) \
+ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+
/* /proc/pid/maps parsing routines */
struct page_content {
char *data;
struct line_content first_line;
unsigned long duration_sec;
int shared_mem_size;
+ int skip_pages;
int page_size;
int vma_count;
bool verbose;
void *child_mapped_addr[];
};
-
-static bool read_two_pages(FIXTURE_DATA(proc_maps_race) *self)
+static bool read_page(FIXTURE_DATA(proc_maps_race) *self,
+ struct page_content *page)
{
ssize_t bytes_read;
- if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
+ bytes_read = read(self->maps_fd, page->data, self->page_size);
+ if (bytes_read <= 0)
return false;
- bytes_read = read(self->maps_fd, self->page1.data, self->page_size);
- if (bytes_read <= 0)
+ /* Make sure data always ends with a newline character. */
+ if (page->data[bytes_read - 1] != '\n')
return false;
- self->page1.size = bytes_read;
+ page->size = bytes_read;
- bytes_read = read(self->maps_fd, self->page2.data, self->page_size);
- if (bytes_read <= 0)
+ return true;
+}
+
+static bool parse_vma_line(char *line_start, char *line_end,
+ unsigned long *start, unsigned long *end)
+{
+ bool found;
+
+ *line_end = '\0'; /* stop sscanf at the EOL */
+ found = (sscanf(line_start, "%lx-%lx", start, end) == 2);
+ *line_end = '\n';
+
+ return found;
+}
+
+static int locate_containing_page(FIXTURE_DATA(proc_maps_race) *self,
+ unsigned long addr, unsigned long size)
+{
+ unsigned long start, end;
+ int page = 0;
+
+ if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ while (true) {
+ char *curr_pos;
+ char *end_pos;
+
+ if (!read_page(self, &self->page1))
+ return -1;
+
+ curr_pos = self->page1.data;
+ end_pos = self->page1.data + self->page1.size;
+ while (curr_pos < end_pos) {
+ char *line_end;
+
+ line_end = strchr(curr_pos, '\n');
+ if (!line_end)
+ break;
+
+ if (parse_vma_line(curr_pos, line_end, &start, &end) &&
+ start == addr && end == addr + size)
+ return page;
+
+ curr_pos = line_end + 1;
+ }
+ page++;
+ }
+
+ return 0;
+}
+
+static bool read_two_pages(FIXTURE_DATA(proc_maps_race) *self)
+{
+ if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
return false;
- self->page2.size = bytes_read;
+ for (int i = 0; i < self->skip_pages; i++)
+ if (!read_page(self, &self->page1))
+ return false;
- return true;
+ return read_page(self, &self->page1) && read_page(self, &self->page2);
}
-static void copy_first_line(struct page_content *page, char *first_line)
+static void copy_line(const char *line_start, const char *line_end,
+ char *buf, size_t buf_size)
{
- char *pos = strchr(page->data, '\n');
+ size_t len = min(line_end - line_start, buf_size - 1);
- strncpy(first_line, page->data, pos - page->data);
- first_line[pos - page->data] = '\0';
+ strncpy(buf, line_start, len);
+ buf[len] = '\0';
}
-static void copy_last_line(struct page_content *page, char *last_line)
+static void copy_first_line(struct page_content *page, char *first_line,
+ size_t line_size)
+{
+ copy_line(page->data, strchr(page->data, '\n'), first_line, line_size);
+}
+
+static void copy_last_line(struct page_content *page, char *last_line,
+ size_t line_size)
{
/* Get the last line in the first page */
const char *end = page->data + page->size - 1;
/* search previous newline */
while (pos[-1] != '\n')
pos--;
- strncpy(last_line, pos, end - pos);
- last_line[end - pos] = '\0';
+
+ copy_line(pos, end, last_line, line_size);
}
/* Read the last line of the first page and the first line of the second page */
if (!read_two_pages(self))
return false;
- copy_last_line(&self->page1, last_line->text);
- copy_first_line(&self->page2, first_line->text);
+ copy_last_line(&self->page1, last_line->text, LINE_MAX_SIZE);
+ copy_first_line(&self->page2, first_line->text, LINE_MAX_SIZE);
return sscanf(last_line->text, "%lx-%lx", &last_line->start_addr,
&last_line->end_addr) == 2 &&
struct vma_modifier_info *mod_info;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
+ unsigned long first_map_addr;
+ unsigned long last_map_addr;
unsigned long duration_sec;
char fname[32];
self->page2.data = malloc(self->page_size);
ASSERT_NE(self->page2.data, NULL);
+ first_map_addr = (unsigned long)mod_info->child_mapped_addr[0];
+ last_map_addr = (unsigned long)mod_info->child_mapped_addr[mod_info->vma_count - 1];
+
+ self->skip_pages = locate_containing_page(self,
+ min(first_map_addr, last_map_addr),
+ self->page_size * 3);
+ ASSERT_NE(self->skip_pages, -1);
ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
/*