Tries to determine the libc version that the file executable (which defaults to the Python interpreter) is linked against. Returns a tuple of strings (lib,version) which default to the given parameters in case the lookup fails. Note that the function has intimate k
(executable=None, lib='', version='', chunksize=16384)
| 159 | |
| 160 | |
| 161 | def libc_ver(executable=None, lib='', version='', chunksize=16384): |
| 162 | |
| 163 | """ Tries to determine the libc version that the file executable |
| 164 | (which defaults to the Python interpreter) is linked against. |
| 165 | |
| 166 | Returns a tuple of strings (lib,version) which default to the |
| 167 | given parameters in case the lookup fails. |
| 168 | |
| 169 | Note that the function has intimate knowledge of how different |
| 170 | libc versions add symbols to the executable and thus is probably |
| 171 | only usable for executables compiled using gcc. |
| 172 | |
| 173 | The file is read and scanned in chunks of chunksize bytes. |
| 174 | |
| 175 | """ |
| 176 | if not executable: |
| 177 | try: |
| 178 | ver = os.confstr('CS_GNU_LIBC_VERSION') |
| 179 | # parse 'glibc 2.28' as ('glibc', '2.28') |
| 180 | parts = ver.split(maxsplit=1) |
| 181 | if len(parts) == 2: |
| 182 | return tuple(parts) |
| 183 | except (AttributeError, ValueError, OSError): |
| 184 | # os.confstr() or CS_GNU_LIBC_VERSION value not available |
| 185 | pass |
| 186 | |
| 187 | executable = sys.executable |
| 188 | |
| 189 | if not executable: |
| 190 | # sys.executable is not set. |
| 191 | return lib, version |
| 192 | |
| 193 | libc_search = re.compile(b'(__libc_init)' |
| 194 | b'|' |
| 195 | b'(GLIBC_([0-9.]+))' |
| 196 | b'|' |
| 197 | br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII) |
| 198 | |
| 199 | V = _comparable_version |
| 200 | # We use os.path.realpath() |
| 201 | # here to work around problems with Cygwin not being |
| 202 | # able to open symlinks for reading |
| 203 | executable = os.path.realpath(executable) |
| 204 | with open(executable, 'rb') as f: |
| 205 | binary = f.read(chunksize) |
| 206 | pos = 0 |
| 207 | while pos < len(binary): |
| 208 | if b'libc' in binary or b'GLIBC' in binary: |
| 209 | m = libc_search.search(binary, pos) |
| 210 | else: |
| 211 | m = None |
| 212 | if not m or m.end() == len(binary): |
| 213 | chunk = f.read(chunksize) |
| 214 | if chunk: |
| 215 | binary = binary[max(pos, len(binary) - 1000):] + chunk |
| 216 | pos = 0 |
| 217 | continue |
| 218 | if not m: |