def get_addr2line(traceback, binfile="", search_dirs=[], shlib_db=None): """ Get the decode of one single OSC traceback via addr2line Note: 1. for DYN type binary, relative offset value is provided to addr2line; 2. for EXEC type binary, absolute address value is provided to addr2line. :param traceback: one traceback in shlib+offset or +offset format :param binfile: the main binary file that prints the traceback :param search_dirs: a list of root directories to search :param shlib_db: the shlib_db obtained via ldd :returns a string containing the "addr2line offset" decode output """ tokens = traceback.split("+") afile = tokens[0] thefile = "" if not afile: thefile = binfile else: if shlib_db and afile in shlib_db: thefile = shlib_db[afile] else: thefile = find_shlib(g_search_dirs, afile) verbose( "decoding traceback: " + traceback + " file: " + afile + " => " + str(thefile), LEVEL_1, ) if not thefile or not os.path.exists(thefile): verbose( "Failed to decode because " + afile + " and " + str(thefile) + " do not exist!", LEVEL_1, ) return traceback + "\n" offset = tokens[1] elf_type = get_elf_type(thefile) verbose(thefile + " elf_type: " + elf_type, LEVEL_1) if elf_type == "EXEC": # Calculate absolute address for EXEC type binary, which is then fed to addr2line base_addr = get_elf_load_base_addr(thefile) verbose( "The LOAD base address or the rounded down entry address is: " + hex(base_addr), LEVEL_1, ) offset = hex(int(offset, 0) + base_addr) # print ("the absolute address is: " + offset) addr2line_prog = get_config_value("addr2line") if not addr2line_prog: addr2line_prog = "addr2line" cmd = addr2line_prog + " -f -i -e " + cmd_quote( thefile) + " " + offset + " || true" verbose("The traceback decode cmd is: " + cmd, LEVEL_1) output = subprocess.check_output(cmd, shell=True, universal_newlines=True, stderr=open(os.devnull, "w")) return output
def get_elf_class(afile): """ Retrieve ELF Class of afile. :param afile: a file :returns the ELF Class of the file """ if afile in g_elf_class_db: return g_elf_class_db[afile] cmd = "readelf -h " + cmd_quote(afile) + ' | grep "Class:" || true' output = get_shell_cmd_output(cmd) tokens = output.split(":") elf_class = tokens[1].strip() verbose(afile + " ELF Class is " + elf_class, LEVEL_2) g_elf_class_db[afile] = elf_class return elf_class
def get_elf_type(afile): """ Retrieve ELF type of afile. :param afile: a file :returns the ELF type of the file """ if afile in g_elf_type_db: return g_elf_type_db[afile] cmd = "readelf -h " + cmd_quote(afile) + ' | grep "Type:" || true' output = get_shell_cmd_output(cmd) tokens = output.split(":") elf_type = tokens[1].split()[0] # verbose(afile + " ELF Type is " + elf_type, LEVEL_2) g_elf_type_db[afile] = elf_type return elf_type
def get_entry_addr(afile): """ Retrieve ELF Entry point address for a file :param afile: a file :returns the ELF Entry point address of the file """ cmd = "readelf -h " + cmd_quote( afile) + ' | grep "Entry point address:" || true' output = get_shell_cmd_output(cmd) if output: tokens = output.split(":") entry_addr = tokens[1].split()[0] # verbose(afile + " entry point address is: " + entry_addr, LEVEL_2) return int(entry_addr, 0) return 0
def parse(self): """ Parse the Alignak configuration file Exit the script if some errors are encountered. :return: None """ config = ConfigParser.ConfigParser() config.read(self.configuration_file) if config._sections == {}: print("Bad formatted configuration file: %s " % self.configuration_file) sys.exit(2) try: for section in config.sections(): if self.verbose: print("Section: %s" % section) for (key, value) in config.items(section): inner_property = "%s.%s" % (section, key) # Set object property setattr(self, inner_property, value) # Set environment variable os.environ[inner_property] = value if self.verbose: print(" %s = %s" % (inner_property, value)) if self.export: # Allowed shell variables may only contain: [a-zA-z0-9_] inner_property = re.sub('[^0-9a-zA-Z]+', '_', inner_property) inner_property = inner_property.upper() print("export %s=%s" % (inner_property, cmd_quote(value))) except ConfigParser.InterpolationMissingOptionError as err: err = str(err) wrong_variable = err.split('\n')[3].split(':')[1].strip() print("Incorrect or missing variable '%s' in config file : %s" % (wrong_variable, self.configuration_file)) sys.exit(3) if self.verbose: print("Configuration file parsed correctly")
def get_all_shlib_paths_via_ldd(afile): """ Get all the shared library paths via the ldd command for a file. :param afile: a file :returns a dictionary that contains all shlib => path mappings. """ cmd = "ldd " + cmd_quote(afile) + " || true" ldd_output = get_shell_cmd_output(cmd) verbose("ldd command: " + cmd + " And output is: " + ldd_output, LEVEL_3) lines = ldd_output.splitlines() shlib_paths = dict() for line in lines: if "=>" not in line: continue tokens = line.split(" => ") shlib = tokens[0].strip() path = tokens[1].split()[0] if os.path.exists(path): shlib_paths[shlib] = path return shlib_paths
def get_elf_load_alignment(afile): """ Get the alignment size of LOAD segment for afile :param afile: a file :returns the alignment size, the default is 2**16=64KB """ default_load_alignment = 2**16 objdump_prog = get_config_value("objdump") if not objdump_prog: objdump_prog = "objdump" cmd = objdump_prog + " -p " + cmd_quote( afile) + " | grep align | grep LOAD || true" output = get_shell_cmd_output(cmd) lines = output.splitlines() if not lines: return default_load_alignment line = lines[0] tokens = line.split(" align ") if len(tokens) < 2: return default_load_alignment alignment = tokens[1] verbose(afile + " LOAD alignment is: " + alignment, LEVEL_1) return eval(alignment)
def parse(self): # pylint: disable=too-many-branches """ Check if some extra configuration files are existing in an `alignak.d` sub directory near the found configuration file. Parse the Alignak configuration file(s) Exit the script if some errors are encountered. :return: True/False """ # Search if some ini files existe in an alignak.d sub-directory sub_directory = 'alignak.d' dir_name = os.path.dirname(self.configuration_file) dir_name = os.path.join(dir_name, sub_directory) self.cfg_files = [self.configuration_file] if os.path.exists(dir_name): for root, _, walk_files in os.walk(dir_name, followlinks=True): for found_file in walk_files: if not re.search(r"\.ini$", found_file): continue self.cfg_files.append(os.path.join(root, found_file)) print("Loading configuration files: %s " % self.cfg_files) # Read and parse the found configuration files self.config = configparser.ConfigParser() try: self.config.read(self.cfg_files) if self.config._sections == {}: print("* bad formatted configuration file: %s " % self.configuration_file) if self.embedded: raise ValueError sys.exit(2) for section in self.config.sections(): if self.verbose: print("- section: %s" % section) for (key, value) in self.config.items(section): inner_property = "%s.%s" % (section, key) # Set object property setattr(self, inner_property, value) # Set environment variable os.environ[inner_property] = value if self.verbose: print(" %s = %s" % (inner_property, value)) if self.export: # Allowed shell variables may only contain: [a-zA-z0-9_] inner_property = re.sub('[^0-9a-zA-Z]+', '_', inner_property) inner_property = inner_property.upper() print("export %s=%s" % (inner_property, cmd_quote(value))) except configparser.ParsingError as exp: print("* parsing error in config file : %s\n%s" % (self.configuration_file, exp.message)) if self.embedded: return False sys.exit(3) except configparser.InterpolationMissingOptionError as exp: print("* incorrect or missing variable: %s" % str(exp)) if self.embedded: return False sys.exit(3) if self.verbose: print("Configuration file parsed correctly") return True