12
12
#include " sanitizer_platform.h"
13
13
14
14
#if SANITIZER_AIX
15
+ # include < assert.h>
16
+ # include < stdlib.h>
15
17
# include < stdio.h>
18
+ # include < sys/procfs.h>
16
19
17
20
# include " sanitizer_common.h"
18
- # include " sanitizer_file.h"
19
21
# include " sanitizer_procmaps.h"
22
+ # include " sanitizer_file.h"
20
23
21
24
namespace __sanitizer {
22
25
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;
24
29
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
+ }
27
38
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;
32
47
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 );
36
51
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 )) {
38
61
proc_maps->data = nullptr ;
39
62
proc_maps->mmaped_size = 0 ;
40
63
proc_maps->len = 0 ;
64
+ proc_maps->mapEnd = nullptr ;
41
65
return ;
42
66
}
43
67
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 );
59
69
}
60
70
61
71
bool MemoryMappingLayout::Next (MemoryMappedSegment *segment) {
62
72
if (Error ())
63
73
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
- }
81
74
82
- if (next_line == 0 )
83
- next_line = last;
75
+ const prmap_t *mapIter = (const prmap_t *)data_.current ;
84
76
85
- // Skip the last line:
86
- // Total 533562K
87
- if (!IsHex (*data_.current ))
77
+ if (mapIter >= data_.proc_self_maps .mapEnd )
88
78
return false ;
89
79
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 ;
93
83
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 ;
96
86
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 ;
100
89
101
- while (data_.current < next_line && *data_.current == ' ' ) data_.current ++;
102
90
segment->protection = 0 ;
103
-
104
- if (*data_. current ++ == ' r ' )
91
+ uint32_t flags = mapIter-> pr_mflags ;
92
+ if (flags & MA_READ )
105
93
segment->protection |= kProtectionRead ;
106
- CHECK (IsOneOf (*data_.current , ' -' , ' w' ));
107
- if (*data_.current ++ == ' w' )
94
+ if (flags & MA_WRITE)
108
95
segment->protection |= kProtectionWrite ;
109
- CHECK (IsOneOf (*data_.current , ' -' , ' x' ));
110
- if (*data_.current ++ == ' x' )
96
+ if (flags & MA_EXEC)
111
97
segment->protection |= kProtectionExecute ;
112
98
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)
125
102
segment->protection |= kProtectionShared ;
126
103
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) {
136
106
// AIX procmap does not print full name for the binary, however when using
137
107
// llvm-symbolizer, it requires the binary must be with full name.
138
108
const char *BinaryName = GetBinaryName ();
@@ -143,20 +113,16 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
143
113
} else {
144
114
// AIX library may exist as xxx.a[yyy.o], to find the path to xxx.a,
145
115
// 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 ;
150
116
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);
154
122
segment->filename [len] = 0 ;
155
-
156
123
// AIX procmap does not print full name for user's library , however when
157
124
// 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) &&
160
126
segment->filename [0 ] != ' /' ) {
161
127
// First check if the library is in the directory where the binary is
162
128
// executed. On AIX, there is no need to put library in same dir with
@@ -191,7 +157,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
191
157
Min ((uptr)(internal_strlen (LibName)), segment->filename_size - 1 );
192
158
internal_strncpy (segment->filename , LibName, len);
193
159
segment->filename [len] = 0 ;
194
- found = true ;
160
+ found = true ;
195
161
}
196
162
CHECK (found);
197
163
}
@@ -200,9 +166,11 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
200
166
segment->filename [0 ] = 0 ;
201
167
}
202
168
169
+ assert (mapIter->pr_off == 0 && " expect a zero offset into module." );
203
170
segment->offset = 0 ;
204
171
205
- data_.current = next_line + 1 ;
172
+ ++mapIter;
173
+ data_.current = (const char *)mapIter;
206
174
207
175
return true ;
208
176
}
0 commit comments