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 inti
(executable=None, lib='', version='', chunksize=16384)
| 159 | br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII) |
| 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 | V = _comparable_version |
| 194 | # We use os.path.realpath() |
| 195 | # here to work around problems with Cygwin not being |
| 196 | # able to open symlinks for reading |
| 197 | executable = os.path.realpath(executable) |
| 198 | with open(executable, 'rb') as f: |
| 199 | binary = f.read(chunksize) |
| 200 | pos = 0 |
| 201 | while pos < len(binary): |
| 202 | if b'libc' in binary or b'GLIBC' in binary: |
| 203 | m = _libc_search.search(binary, pos) |
| 204 | else: |
| 205 | m = None |
| 206 | if not m or m.end() == len(binary): |
| 207 | chunk = f.read(chunksize) |
| 208 | if chunk: |
| 209 | binary = binary[max(pos, len(binary) - 1000):] + chunk |
| 210 | pos = 0 |
| 211 | continue |
| 212 | if not m: |
| 213 | break |
| 214 | libcinit, glibc, glibcversion, so, threads, soversion = [ |
| 215 | s.decode('latin1') if s is not None else s |
| 216 | for s in m.groups()] |
| 217 | if libcinit and not lib: |
| 218 | lib = 'libc' |