Skip to content

Commit 28617e2

Browse files
committed
Don't use procmap utility
1 parent 7baf1c4 commit 28617e2

File tree

2 files changed

+69
-97
lines changed

2 files changed

+69
-97
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_aix.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
# include "sanitizer_common.h"
1919
# include "sanitizer_posix.h"
2020

21+
struct prmap;
22+
typedef struct prmap prmap_t;
23+
2124
namespace __sanitizer {
2225

2326
# if SANITIZER_WORDSIZE == 32
@@ -30,6 +33,7 @@ struct ProcSelfMapsBuff {
3033
char *data;
3134
uptr mmaped_size;
3235
uptr len;
36+
prmap_t *mapEnd;
3337
};
3438

3539
struct MemoryMappingLayoutData {

compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp

Lines changed: 65 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -12,127 +12,97 @@
1212
#include "sanitizer_platform.h"
1313

1414
#if SANITIZER_AIX
15+
# include <assert.h>
16+
# include <stdlib.h>
1517
# include <stdio.h>
18+
# include <sys/procfs.h>
1619

1720
# include "sanitizer_common.h"
18-
# include "sanitizer_file.h"
1921
# include "sanitizer_procmaps.h"
22+
# include "sanitizer_file.h"
2023

2124
namespace __sanitizer {
2225

23-
static bool IsOneOf(char c, char c1, char c2) { return c == c1 || c == c2; }
26+
static int qsort_comp(const void *va, const void * vb) {
27+
const prmap_t *a = (const prmap_t *)va;
28+
const prmap_t *b = (const prmap_t *)vb;
2429

25-
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
26-
uptr pid = internal_getpid();
30+
if (a->pr_vaddr < b->pr_vaddr)
31+
return -1;
32+
33+
if (a->pr_vaddr > b->pr_vaddr)
34+
return 1;
35+
36+
return 0;
37+
}
2738

28-
// The mapping in /proc/id/map is not ordered by address, this will hit some
29-
// issue when checking stack base and size. Howevern AIX procmap can generate
30-
// sorted ranges.
31-
char Command[100] = {};
39+
static prmap_t *SortProcMapEntries(char *buffer) {
40+
prmap_t *begin = (prmap_t*)buffer;
41+
prmap_t *mapIter = begin;
42+
// The AIX procmap utility detects the end of the array of `prmap`s by finding
43+
// an entry where pr_size and pr_vaddr are both zero.
44+
while (mapIter->pr_size != 0 || mapIter->pr_vaddr != 0)
45+
++mapIter;
46+
prmap_t *end = mapIter;
3247

33-
internal_snprintf(Command, 100, "procmap -qX %d", pid);
34-
// Open pipe to file
35-
__sanitizer_FILE *pipe = internal_popen(Command, "r");
48+
size_t count = end - begin;
49+
size_t elemSize = sizeof(prmap_t);
50+
qsort(begin, count, elemSize, qsort_comp);
3651

37-
if (!pipe) {
52+
return end;
53+
}
54+
55+
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
56+
uptr pid = internal_getpid();
57+
constexpr unsigned BUFFER_SIZE = 128;
58+
char filenameBuf[BUFFER_SIZE] = {};
59+
internal_snprintf(filenameBuf, BUFFER_SIZE, "/proc/%d/map", pid);
60+
if (!ReadFileToBuffer(filenameBuf, &proc_maps->data, &proc_maps->mmaped_size, &proc_maps->len)) {
3861
proc_maps->data = nullptr;
3962
proc_maps->mmaped_size = 0;
4063
proc_maps->len = 0;
64+
proc_maps->mapEnd = nullptr;
4165
return;
4266
}
4367

44-
char buffer[512] = {};
45-
46-
InternalScopedString Data;
47-
while (fgets(buffer, 512, reinterpret_cast<FILE *>(pipe)) != nullptr)
48-
Data.Append(buffer);
49-
50-
size_t MmapedSize = Data.length() * 4 / 3;
51-
void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
52-
internal_memcpy(VmMap, Data.data(), Data.length());
53-
54-
proc_maps->data = (char *)VmMap;
55-
proc_maps->mmaped_size = MmapedSize;
56-
proc_maps->len = Data.length();
57-
58-
internal_pclose(pipe);
68+
proc_maps->mapEnd = SortProcMapEntries(proc_maps->data);
5969
}
6070

6171
bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
6272
if (Error())
6373
return false; // simulate empty maps
64-
char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
65-
if (data_.current >= last)
66-
return false;
67-
char *next_line =
68-
(char *)internal_memchr(data_.current, '\n', last - data_.current);
69-
70-
// Skip the first header line and the second kernel line
71-
// pid : binary name
72-
if (data_.current == data_.proc_self_maps.data) {
73-
data_.current = next_line + 1;
74-
next_line =
75-
(char *)internal_memchr(next_line + 1, '\n', last - data_.current);
76-
77-
data_.current = next_line + 1;
78-
next_line =
79-
(char *)internal_memchr(next_line + 1, '\n', last - data_.current);
80-
}
8174

82-
if (next_line == 0)
83-
next_line = last;
75+
const prmap_t *mapIter = (const prmap_t *)data_.current;
8476

85-
// Skip the last line:
86-
// Total 533562K
87-
if (!IsHex(*data_.current))
77+
if (mapIter >= data_.proc_self_maps.mapEnd)
8878
return false;
8979

90-
// Example: 10000000 10161fd9 1415K r-x s MAINTEXT 151ed82 a.out
91-
segment->start = ParseHex(&data_.current);
92-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
80+
// Skip the kernel segment.
81+
if ((mapIter->pr_mflags & MA_TYPE_MASK) == MA_KERNTEXT)
82+
++mapIter;
9383

94-
segment->end = ParseHex(&data_.current);
95-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
84+
if (mapIter >= data_.proc_self_maps.mapEnd)
85+
return false;
9686

97-
// Ignore the size, we can get accurate size from end and start
98-
while (IsDecimal(*data_.current)) data_.current++;
99-
CHECK_EQ(*data_.current++, 'K');
87+
segment->start = (uptr)mapIter->pr_vaddr;
88+
segment->end = segment->start + mapIter->pr_size;
10089

101-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
10290
segment->protection = 0;
103-
104-
if (*data_.current++ == 'r')
91+
uint32_t flags = mapIter->pr_mflags;
92+
if (flags & MA_READ)
10593
segment->protection |= kProtectionRead;
106-
CHECK(IsOneOf(*data_.current, '-', 'w'));
107-
if (*data_.current++ == 'w')
94+
if (flags & MA_WRITE)
10895
segment->protection |= kProtectionWrite;
109-
CHECK(IsOneOf(*data_.current, '-', 'x'));
110-
if (*data_.current++ == 'x')
96+
if (flags & MA_EXEC)
11197
segment->protection |= kProtectionExecute;
11298

113-
// Ignore the PSIZE(s/m/L/H)
114-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
115-
data_.current += 4;
116-
117-
// Get the region TYPE
118-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
119-
char Type[16] = {};
120-
uptr len = 0;
121-
while (*data_.current != ' ') Type[len++] = *data_.current++;
122-
Type[len] = 0;
123-
124-
if (!internal_strcmp(Type, "SLIBTEXT") || !internal_strcmp(Type, "PLIBDATA"))
99+
// TODO FIXME why not PLIBTEXT?
100+
uint32_t type = mapIter->pr_mflags & MA_TYPE_MASK;
101+
if (type == MA_SLIBTEXT || type == MA_PLIBDATA)
125102
segment->protection |= kProtectionShared;
126103

127-
// Ignore the VSID
128-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
129-
ParseHex(&data_.current);
130-
131-
while (data_.current < next_line && *data_.current == ' ') data_.current++;
132-
133-
if (segment->filename && data_.current != next_line) {
134-
if (!internal_strcmp(Type, "MAINDATA") ||
135-
!internal_strcmp(Type, "MAINTEXT")) {
104+
if (segment->filename && mapIter->pr_pathoff) {
105+
if (type == MA_MAINDATA || type == MA_MAINEXEC) {
136106
// AIX procmap does not print full name for the binary, however when using
137107
// llvm-symbolizer, it requires the binary must be with full name.
138108
const char *BinaryName = GetBinaryName();
@@ -143,20 +113,16 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
143113
} else {
144114
// AIX library may exist as xxx.a[yyy.o], to find the path to xxx.a,
145115
// the [yyy.o] part needs to be removed.
146-
char *NameEnd = (char *)internal_memchr(data_.current, '[',
147-
next_line - data_.current);
148-
if (!NameEnd)
149-
NameEnd = next_line - 1;
150116

151-
uptr len =
152-
Min((uptr)(NameEnd - data_.current), segment->filename_size - 1);
153-
internal_strncpy(segment->filename, data_.current, len);
117+
// TODO FIXME
118+
const char *pathPtr = data_.proc_self_maps.data + mapIter->pr_pathoff;
119+
uptr len = Min((uptr)internal_strlen(pathPtr),
120+
segment->filename_size - 1);
121+
internal_strncpy(segment->filename, pathPtr, len);
154122
segment->filename[len] = 0;
155-
156123
// AIX procmap does not print full name for user's library , however when
157124
// use llvm-symbolizer, it requires the library must be with full name.
158-
if ((!internal_strcmp(Type, "SLIBTEXT") ||
159-
!internal_strcmp(Type, "PLIBDATA")) &&
125+
if ((type == MA_SLIBTEXT || type == MA_PLIBDATA) &&
160126
segment->filename[0] != '/') {
161127
// First check if the library is in the directory where the binary is
162128
// executed. On AIX, there is no need to put library in same dir with
@@ -191,7 +157,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
191157
Min((uptr)(internal_strlen(LibName)), segment->filename_size - 1);
192158
internal_strncpy(segment->filename, LibName, len);
193159
segment->filename[len] = 0;
194-
found = true;
160+
found = true;
195161
}
196162
CHECK(found);
197163
}
@@ -200,9 +166,11 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
200166
segment->filename[0] = 0;
201167
}
202168

169+
assert(mapIter->pr_off == 0 && "expect a zero offset into module.");
203170
segment->offset = 0;
204171

205-
data_.current = next_line + 1;
172+
++mapIter;
173+
data_.current = (const char*)mapIter;
206174

207175
return true;
208176
}

0 commit comments

Comments
 (0)