Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # | |
| 3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file | |
| 6 | |
| 7 import base64 | |
| 8 import os | |
| 9 import sys | |
| 10 import re | |
| 11 | |
| 12 from optparse import OptionParser | |
| 13 | |
| 14 """ Extracts the list of resident symbols of a library loaded in a process. | |
|
bulach
2013/07/22 12:59:39
nit: remove space before Extracts
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
| |
| 15 | |
| 16 This scripts combines the extended output of memdump for a given process | |
| 17 (obtained through memdump -x PID) and the symbol table of a .so loaded in that | |
| 18 process (obtained through nm -C lib-with-symbols.so), filtering out only those | |
| 19 symbols that, at the time of the snapshot, were resident in memory (that are, | |
| 20 the symbols which start address belongs to a mapped page of the .so which was | |
| 21 resident at the time of the snapshot). | |
| 22 The aim is to perform a "code coverage"-like profiling of a binary, intersecting | |
| 23 run-time information (list of resident pages) and debug symbols. | |
| 24 """ | |
| 25 | |
| 26 PAGE_SIZE = 4096 | |
|
bulach
2013/07/22 12:59:39
nit: _ prefix.
also, below should be _TestBit and
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
| |
| 27 | |
| 28 def test_bit(word, bit): | |
| 29 assert(bit >= 0 and bit < 8) | |
| 30 return not not ((word >> bit) & 1) | |
| 31 | |
| 32 def hex_addr(addr): | |
| 33 return hex(addr)[2:].zfill(8) | |
| 34 | |
| 35 def main(argv): | |
| 36 MAP_RX = re.compile( | |
| 37 r'^([0-9a-f]+)-([0-9a-f]+) ([\w-]+) ([0-9a-f]+) .* "(.*)" \[(.*)\]$') | |
| 38 NM_RX = re.compile(r'^([0-9a-f]+)\s+\w+\s+.*$') | |
| 39 | |
| 40 parser = OptionParser() | |
| 41 parser.add_option("-r", "--reverse", | |
| 42 action="store_true", dest="reverse", default=False, | |
| 43 help="Print out non present symbols") | |
| 44 parser.add_option("-v", "--verbose", | |
| 45 action="store_true", dest="verbose", default=False, | |
| 46 help="Print out verbose debug information.") | |
| 47 | |
| 48 (options, args) = parser.parse_args() | |
| 49 | |
| 50 if len(args) != 3: | |
| 51 print 'Usage: %s [-v] memdump.file nm.file library.so' % ( | |
| 52 os.path.basename(argv[0])) | |
| 53 return 1 | |
| 54 | |
|
bulach
2013/07/22 12:59:39
it'd be nicer to split 54-134 into its own functio
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
| |
| 55 memdump_file = args[0] | |
| 56 nm_file = args[1] | |
| 57 lib_name = args[2] | |
| 58 resident_pages = set() | |
| 59 | |
| 60 # First process the memdump output and extract the mappings which match the | |
| 61 # given library name. | |
| 62 memdump_fh = open(memdump_file, 'r') | |
|
Philippe
2013/07/22 09:20:55
Nit: will this work with stdin?
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Added special '-' handling to read memdump from st
pliard
2013/07/23 09:08:22
Nice, thanks.
| |
| 63 for line in memdump_fh: | |
| 64 line = line.rstrip('\r\n') | |
| 65 if line.startswith('[ PID'): | |
| 66 continue | |
| 67 | |
| 68 r = MAP_RX.match(line) | |
| 69 if not r: | |
| 70 sys.stderr.write('Skipping %s from %s\n' % (line, nm_file)) | |
| 71 continue | |
| 72 | |
| 73 map_start = int(r.group(1), 16) | |
| 74 map_end = int(r.group(2), 16) | |
| 75 prot = r.group(3) | |
| 76 offset = int(r.group(4), 16) | |
| 77 assert(offset % PAGE_SIZE == 0) | |
| 78 lib = r.group(5) | |
| 79 enc_bitmap = r.group(6) | |
| 80 | |
| 81 #if prot == 'r-xp': | |
|
Philippe
2013/07/22 09:20:55
Nit: should we keep this? :)
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
| |
| 82 # continue | |
| 83 if not lib.endswith(lib_name): | |
| 84 continue | |
| 85 | |
| 86 bitmap = base64.b64decode(enc_bitmap) | |
| 87 map_pages_count = (map_end - map_start + 1) / PAGE_SIZE | |
| 88 bitmap_pages_count = len(bitmap) * 8 | |
| 89 | |
| 90 if options.verbose: | |
| 91 print 'Found %s: mapped %d pages in mode %s @ offset %s.' % ( | |
| 92 lib, map_pages_count, prot, hex_addr(offset)) | |
| 93 print ' Map range in the process VA: [%s - %s]. Len: %s' % ( | |
| 94 hex_addr(map_start), | |
| 95 hex_addr(map_end), | |
| 96 hex_addr(map_pages_count * PAGE_SIZE)) | |
| 97 print ' Corresponding addresses in the binary: [%s - %s]. Len: %s' % ( | |
| 98 hex_addr(offset), | |
| 99 hex_addr(offset + map_end - map_start), | |
| 100 hex_addr(map_pages_count * PAGE_SIZE)) | |
| 101 print ' Bitmap: %d pages' % bitmap_pages_count | |
| 102 print '' | |
| 103 | |
| 104 assert(bitmap_pages_count >= map_pages_count) | |
| 105 for i in xrange(map_pages_count): | |
| 106 bitmap_idx = i / 8 | |
| 107 bitmap_off = i % 8 | |
| 108 if (bitmap_idx < len(bitmap) and | |
| 109 test_bit(ord(bitmap[bitmap_idx]), bitmap_off)): | |
| 110 resident_pages.add(offset/PAGE_SIZE + i) | |
|
Philippe
2013/07/22 09:20:55
Nit: spaces around binary operators (also on line
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
Done.
| |
| 111 | |
| 112 # Now process the nm symbol table, filtering out the resident symbols. | |
| 113 nm_fh = open(nm_file, 'r') | |
| 114 last_sym_matched = False | |
| 115 for line in nm_fh: | |
| 116 line = line.rstrip('\r\n') | |
| 117 if line.startswith(' '): | |
| 118 if last_sym_matched: | |
| 119 print line | |
| 120 continue | |
| 121 | |
| 122 r = NM_RX.match(line) | |
| 123 if not r: | |
| 124 sys.stderr.write('Skipping %s from %s\n' % (line, nm_file)) | |
| 125 continue | |
| 126 | |
| 127 sym_addr = int(r.group(1),16) | |
| 128 sym_page = sym_addr / PAGE_SIZE | |
| 129 last_sym_matched = (sym_page in resident_pages) | |
| 130 if options.reverse: | |
| 131 last_sym_matched = not last_sym_matched | |
| 132 if last_sym_matched: | |
| 133 print line | |
| 134 | |
| 135 if __name__=='__main__': | |
| 136 main(sys.argv) | |
|
bulach
2013/07/22 12:59:39
nit: return main(sys.argv)
Primiano Tucci (use gerrit)
2013/07/22 23:22:35
You mean sys.exit, right?
bulach
2013/07/23 08:10:57
yep, thanks!
| |
| OLD | NEW |