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
2124namespace __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
6171bool 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