def ParseSymbolFile(symFile): try: symbolMap = {} publicCount = 0 funcCount = 0 for lineNum, line in enumerate(symFile.readlines()): if line[0:7] == "PUBLIC ": line = line.rstrip() fields = line.split(" ") if len(fields) < 4: LogDebug("Line " + str(lineNum + 1) + " is messed") continue address = int(fields[1], 16) symbolMap[address] = " ".join(fields[3:]) publicCount += 1 elif line[0:5] == "FUNC ": line = line.rstrip() fields = line.split(" ") if len(fields) < 5: LogDebug("Line " + str(lineNum + 1) + " is messed") continue address = int(fields[1], 16) symbolMap[address] = " ".join(fields[4:]) funcCount += 1 except Exception as e: LogError("Error parsing SYM file {}: {}".format(symFile, e)) return None logString = "Found " + str(len(symbolMap.keys())) + " unique entries from " logString += str(publicCount) + " PUBLIC lines, " + str( funcCount) + " FUNC lines" LogDebug(logString) return SymbolInfo(symbolMap)
def getModuleV3(libName, breakpadId): if not isinstance(libName, basestring) or not gLibNameRE.match(libName): LogDebug("Bad library name: " + str(libName)) return None if not isinstance(breakpadId, basestring): LogDebug("Bad breakpad id: " + str(breakpadId)) return None return (libName, breakpadId)
def FetchSymbolsFromFile(self, path): try: with open(path, "r") as symFile: LogMessage("Parsing SYM file at " + path) return ParseSymbolFile(symFile) except Exception as e: LogDebug("Error opening file " + path + ": " + str(e)) return None
def Evict(self, libs): for libName, breakpadId in libs: path = self.MakePath(libName, breakpadId) # Remove from the disk LogDebug("Evicting {} from disk cache.".format(path)) try: os.remove(path) except OSError: pass
def Fetch(self, lib): for fetcher in self.fetchPipeline: libSymbolMap = fetcher.Fetch(lib[0], lib[1]) if libSymbolMap: return libSymbolMap else: LogDebug("No matching sym files, tried paths: %s and URLs: %s" % \ (", ".join(self.sOptions["symbolPaths"]), ", ".join(self.sOptions["symbolURLs"]))) return None
def GetLibSymbolMaps(self, libs): symbols = {} for lib in libs: # Empty lib name means client couldn't associate frame with any lib if lib[0]: symbol = self.GetLibSymbolMap(lib) if symbol: symbols[lib] = symbol newMRU = self.UpdateMRU(symbols) self.diskCache.Update(self.MRU, newMRU, symbols) self.memoryCache.Update(self.MRU, newMRU, symbols) self.MRU = newMRU LogDebug("Memory cache size = {}".format(len(self.memoryCache.sCache))) LogDebug("Disk cache size = {}".format(len(self.MRU))) return symbols
def Fetch(self, libName, breakpadId): LogDebug("Fetching [{}] [{}] in remote URLs".format(libName, breakpadId)) symFileName = GetSymbolFileName(libName) urlSuffix = "/".join([libName, breakpadId, symFileName]) for symbolURL in self.sOptions["symbolURLs"]: url = urlparse.urljoin(symbolURL, urlSuffix) libSymbolMap = self.FetchSymbolsFromURL(url) if libSymbolMap: return libSymbolMap else: return None
def Fetch(self, libName, breakpadId): LogDebug("Fetching [{}] [{}] in local paths".format(libName, breakpadId)) symFileName = GetSymbolFileName(libName) pathSuffix = os.path.join(libName, breakpadId, symFileName) for symbolPath in self.sOptions["symbolPaths"]: path = os.path.join(symbolPath, pathSuffix) libSymbolMap = self.FetchSymbolsFromFile(path) if libSymbolMap: return libSymbolMap else: return None
def LoadCacheEntries(self, MRU, diskCache): LogMessage("Initializing memory cache from disk cache") for lib in MRU[:self.MAX_SIZE]: LogDebug("Loading library " + str(lib)) cachedLib = diskCache.Get(lib) if cachedLib: self.sCache[lib] = diskCache.Get(lib) else: # this is safe, iterating over a "copy" of the MRU because of slice operator MRU.remove(lib) LogMessage("Finished initializing memory cache from disk cache")
def Get(self, lib): path = self.MakePath(lib[0], lib[1]) symbolInfo = None try: with open(path, 'rb') as f: symbolInfo = pickle.load(f) except (IOError, pickle.PickleError) as ex: LogDebug("Could not load pickled lib [{}] [{}]: {}".format( lib[0], lib[1], ex)) return symbolInfo
def Update(self, oldMRU, newMRU, symbols): maxSize = self.MAX_SIZE oldMruSet = set(oldMRU[:maxSize]) newMruSet = set(newMRU[:maxSize]) inserted = newMruSet.difference(oldMruSet) evicted = oldMruSet.difference(newMruSet) LogDebug("Evicting {} and inserting {} entries in {}".format( len(evicted), len(inserted), self.__class__)) self.Evict(evicted) self.Insert(inserted, symbols)
def GetLibSymbolMap(self, lib): try: index = self.MRU.index(lib) except ValueError: return self.Fetch(lib) if index < self.memoryCache.MAX_SIZE: cache = self.memoryCache else: cache = self.diskCache LogDebug("Loading [{}] [{}] from {}".format(lib[0], lib[1], cache.__class__)) libSymbolMap = cache.Get(lib) if libSymbolMap is None: libSymbolMap = self.Fetch(lib) return libSymbolMap
def FetchSymbolsFromURL(self, url): try: with contextlib.closing(urllib2.urlopen(url)) as request: if request.getcode() != 200: return None headers = request.info() contentEncoding = headers.get("Content-Encoding", "").lower() if contentEncoding in ("gzip", "x-gzip", "deflate"): data = request.read() # We have to put it in a string IO because gzip looks for # the "tell()" file object method request = StringIO(data) try: with gzip.GzipFile(fileobj=request) as f: request = StringIO(f.read()) except Exception: request = StringIO(data.decode('zlib')) LogMessage("Parsing SYM file at " + url) return ParseSymbolFile(request) except Exception as e: LogDebug("Error opening URL " + url + ": " + str(e)) return None
def LogDebug(self, string): LogDebug(string, self.remoteIp)