Example #1
0
    def do_info(self, args):
        """List the details of a code item (tool or component).

		code info NAME_OR_ID
		"""
        parser = self._argparser()
        parser.add_argument("name_or_id")
        parser.add_argument("--tools",
                            "-t",
                            default=False,
                            action="store_true")
        parser.add_argument("--components",
                            "-c",
                            default=False,
                            action="store_true")

        args = parser.parse_args(shlex.split(args))

        if args.tools and args.components:
            raise errors.TalusApiError("must specify only -t or -c")

        search = {}
        if args.tools:
            search["type"] = "tool"
        if args.components:
            search["type"] = "component"

        code = self._talus_client.code_find(args.name_or_id, **search)

        if code is None:
            raise errors.TalusApiError(
                "could not find talus code named {!r}".format(args.name_or_id))

        print("""
    ID: {id}
  Name: {name}
 Bases: {bases}
  Type: {type}
		""".format(id=code.id,
             name=code.name,
             bases=" ".join(code.bases),
             type=code.type.capitalize())[0:-3])

        params_nice = []
        for param in code.params:
            if param["type"]["type"] == "native":
                param_type = param["type"]["name"]
            elif param["type"]["type"] == "component":
                param_type = "Component({})".format(param["type"]["name"])
            else:
                param_type = param["type"]["name"]
            params_nice.append([param_type, param["name"], param["desc"]])

        params = tabulate(params_nice, headers=["type", "name", "desc"])
        print("Params:\n\n" + "\n".join("    " + p
                                        for p in params.split("\n")) + "\n")
Example #2
0
    def do_get(self, args):
        """Get the file(s) from the corpus with the provided id(s), saving to the
		current directory if no destination path is provided (works like cp and mv)

		Example:

		To fetch a single file and save it into /tmp:

			corpus get 55cdcbaedd18da0008caa793 /tmp

		To fetch multiple files and save to /tmp:

			corpus get 55cdcbaedd18da0008caa793 55cdcbaedd18da0008caa794 55cdcbaedd18da0008caa795 /tmp
		"""
        parts = shlex.split(args)

        if len(parts) == 0:
            raise errors.TalusApiError("At least one id must be provided")

        if len(parts) > 1:
            dest = parts[-1]
            file_ids = parts[:-1]
        else:
            dest = None
            file_ids = [parts[0]]

        if dest is None:
            dest = "./"

        full_dest = os.path.abspath(os.path.expanduser(dest))

        # it needs to be a directory for this to work
        if len(file_ids) > 1 and (not os.path.exists(full_dest)
                                  or not os.path.isdir(full_dest)):
            raise errors.TalusApiError(
                "Destination for multiple files must exist _and_ be a directory!"
            )

        for file_id in file_ids:
            fname, data = self._talus_client.corpus_get(file_id)

            if len(file_ids) > 1 or os.path.isdir(full_dest):
                unexpanded_dest = os.path.join(dest, fname)
                write_dest = os.path.join(full_dest, fname)
            else:
                unexpanded_dest = dest
                write_dest = full_dest

            with open(write_dest, "wb") as f:
                f.write(data)

            print("{} saved to {} ({} bytes)".format(file_id, unexpanded_dest,
                                                     len(data)))
Example #3
0
	def do_edit(self, args):
		"""Edit an existing image. Interactive mode only
		"""
		if args.strip() == "":
			raise errors.TalusApiError("you must provide a name/id of an image to edit it")

		parts = shlex.split(args)
		leftover = []
		image_id_or_name = None
		search = self._search_terms(parts, out_leftover=leftover)
		if len(leftover) > 0:
			image_id_or_name = leftover[0]

		image = self._resolve_one_model(image_id_or_name, Image, search)

		if image is None:
			raise errors.TalusApiError("could not find talus image with id {!r}".format(image_id_or_name))

		while True:
			model_cmd = self._make_model_cmd(image)
			cancelled = model_cmd.cmdloop()
			if cancelled:
				break

			error = False
			if image.os is None:
				self.err("You must specify the os")
				error = True

			if image.name is None or image.name == "":
				self.err("You must specify a name for the image")
				error = True

			if image.base_image is None:
				self.err("You must specify the base_image for your new image")
				error = True

			if error:
				continue

			try:
				image.timestamps = {"modified": time.time()}
				image.save()
				self.ok("edited image {}".format(image.id))
				self.ok("note that this DOES NOT start the image for configuring!")
			except errors.TalusApiError as e:
				self.err(e.message)

			return
Example #4
0
	def delete(self):
		"""Delete this model
		"""
		res = utils.json_request(requests.delete, self._id_url())
		if res.status_code // 100 != 2:
			raise errors.TalusApiError("Could not delete model", error=res.text)
		self._fields = {}
Example #5
0
    def _resolve_one_model(self,
                           id_or_name,
                           model,
                           search,
                           sort="-timestamps.created",
                           default_id_search=None):
        if default_id_search is None:
            default_id_search = ["id", "name"]

        if id_or_name is not None and not id_or_name.startswith("+"):
            for default_compare in default_id_search:
                res = model.find_one(**{default_compare: id_or_name})
                if res is not None:
                    return res
            return None

        if id_or_name is None:
            skip = 0
        else:
            if not re.match(r'^\+\d+$', id_or_name):
                raise errors.TalusApiError(
                    "Git-like referencing must be a plus sign followed by digits"
                )
            skip = int(id_or_name.replace("+", "")) - 1
        search["skip"] = skip
        search["num"] = 1
        search["sort"] = sort
        return model.find_one(**search)
Example #6
0
    def do_delete(self, args):
        """Delete the file specified by the provided id
		"""
        parts = shlex.split(args)
        if len(parts) == 0:
            raise errors.TalusApiError(
                "You must provide the id of the file to delete")

        file_id = parts[0]
        res = self._talus_client.corpus_delete(file_id)
        if "error" in res:
            raise errors.TalusApiError(
                "Could not delete file id {!r}: {}".format(
                    file_id,
                    res["error"],
                ))

        print("deleted")
Example #7
0
	def refresh(self):
		"""Refresh the current model
		"""
		if "id" not in self._fields:
			return
		matches = self.objects_raw(api_base=self.api_base, id=self.id)
		if len(matches) == 0:
			raise errors.TalusApiError("Error! current model no longer exists!")
		update = matches[0]
		self._populate(update)
Example #8
0
    def do_create(self, args):
        """Create new code in the repository. This will create the code in the talus
		repository, as well as in the database.

		code create NAME -t or -c

		     -t,--tool    Create a tool
		-c,--component    Create a component
		"""
        args = shlex.split(args)
        parser = self._argparser()
        parser.add_argument("name")
        parser.add_argument("--tool", "-t", default=False, action="store_true")
        parser.add_argument("--component",
                            "-c",
                            default=False,
                            action="store_true")
        parser.add_argument("--tag", dest="tags", action="append")

        args = parser.parse_args(args)

        if not args.tool and not args.component:
            raise errors.TalusApiError(
                "must specify either a tool or a component, non specified")

        if args.tool and args.component:
            raise errors.TalusApiError(
                "must specify either a tool or a component, non both")

        if args.tool:
            code_type = "tool"
        else:
            code_type = "component"

        res = self._talus_client.code_create(code_name=args.name,
                                             code_type=code_type,
                                             tags=args.tags)

        if res["status"] == "error":
            self.err(res["message"])
        else:
            self.ok(res["message"])
Example #9
0
    def do_info(self, args):
        """List details about a task
		"""
        if args.strip() == "":
            raise errors.TalusApiError(
                "you must provide a name/id of a task to show info about it")

        parts = shlex.split(args)
        leftover = []
        task_id_or_name = None
        search = self._search_terms(parts, out_leftover=leftover)
        if len(leftover) > 0:
            task_id_or_name = leftover[0]

        task = self._resolve_one_model(task_id_or_name, Task, search)

        if task is None:
            raise errors.TalusApiError(
                "could not find talus task with id {!r}".format(
                    task_id_or_name))
Example #10
0
def json_request(method, *args, **params):
	content_type = "application/json"

	if "data" in params and hasattr(params["data"], "content_type"):
		content_type = params["data"].content_type

	params.setdefault("headers", {}).setdefault("content-type", content_type)

	try:
		res = method(*args, **params)
	except requests.ConnectionError as e:
		raise errors.TalusApiError("Could not connect to {}".format(args[0]))
	except Exception as e:
		return None

	return res
Example #11
0
    def do_edit(self, args):
        """Edit an existing task in Talus. Interactive mode only
		"""
        if args.strip() == "":
            raise errors.TalusApiError(
                "you must provide a name/id of a task to edit it")

        parts = shlex.split(args)
        leftover = []
        task_id_or_name = None
        search = self._search_terms(parts, out_leftover=leftover)
        if len(leftover) > 0:
            task_id_or_name = leftover[0]

        task = self._resolve_one_model(task_id_or_name, Task, search)

        self._interactive_loop(task)
Example #12
0
	def save(self):
		"""Save this model's fields
		"""
		files = None
		data = json.dumps(self._filtered_fields())

		if "id" in self._fields:
			res = utils.json_request(
				requests.put,
				self._id_url(),
				data=data
			)
		else:
			res = utils.json_request(
				requests.post,
				self.api_url(self.api_base),
				data=data
			)

		# yes, that's intentional (the //) - look it up
		if res.status_code // 100 != 2:
			raise errors.TalusApiError("Could not save model", error=res.text)

		self._populate(res.json())
Example #13
0
	def do_create(self, args):
		"""Create a new image in talus using an existing base image. Anything not explicitly
		specified will be inherited from the base image, except for the name, which is required.

		create -n NAME -b BASEID_NAME [-d DESC] [-t TAG1,TAG2,..] [-u USER] [-p PASS] [-o OSID] [-i]

			     -o,--os    ID or name of the operating system model
		       -b,--base    ID or name of the base image
		       -n,--name    The name of the resulting image (default: basename(FILE))
			   -d,--desc    A description of the image (default: "")
			   -t,--tags    Tags associated with the image (default: [])
			     --shell    Forcefully drop into an interactive shell
		-v,--vagrantfile    A vagrant file that will be used to congfigure the image
		-i,--interactive    To interact with the imported image for setup (default: False)

		Examples:

		To create a new image based on the image with id 222222222222222222222222 and adding
		a new description and allowing for manual user setup:

			image create -b 222222222222222222222222 -d "some new description" -i
		"""
		args = shlex.split(args)
		if self._go_interactive(args):
			image = Image()
			self._prep_model(image)
			image.username = "******"
			image.password = "******"
			image.md5 = " "
			image.desc = "some description"
			image.status = {
				"name": "create",
				"vagrantfile": None,
				"user_interaction": True
			}

			while True:
				model_cmd = self._make_model_cmd(image)
				model_cmd.add_field(
					"interactive",
					Field(True),
					lambda x,v: x.status.update({"user_interaction": v}),
					lambda x: x.status["user_interaction"],
					desc="If the image requires user interaction for configuration",
				)
				model_cmd.add_field(
					"vagrantfile",
					Field(str),
					lambda x,v: x.status.update({"vagrantfile": open(v).read()}),
					lambda x: x.status["vagrantfile"],
					desc="The path to the vagrantfile that will configure the image"
				)
				cancelled = model_cmd.cmdloop()
				if cancelled:
					break

				error = False
				if image.os is None:
					self.err("You must specify the os")
					error = True

				if image.name is None or image.name == "":
					self.err("You must specify a name for the image")
					error = True

				if image.base_image is None:
					self.err("You must specify the base_image for your new image")
					error = True

				if error:
					continue

				try:
					image.timestamps = {"created": time.time()}
					image.save()
					self.ok("created new image {}".format(image.id))
				except errors.TalusApiError as e:
					self.err(e.message)
				else:
					self._wait_for_image(image, image.status["user_interaction"])

				return

		parser = self._argparser()
		parser.add_argument("--os", "-o", default=None)
		parser.add_argument("--base", "-b", default=None)
		parser.add_argument("--name", "-n", default=None)
		parser.add_argument("--desc", "-d", default="")
		parser.add_argument("--tags", "-t", default="")
		parser.add_argument("--vagrantfile", "-v", default=None, type=argparse.FileType("rb"))
		parser.add_argument("--interactive", "-i", action="store_true", default=False)

		args = parser.parse_args(args)

		if args.name is None:
			raise errors.TalusApiError("You must specify an image name")

		vagrantfile_contents = None
		if args.vagrantfile is not None:
			vagrantfile_contents = args.vagrantfile.read()

		if args.tags is not None:
			args.tags = args.tags.split(",")

		error = False
		validation = {
			"os"	: "You must set the os",
			"base"	: "You must set the base",
			"name"	: "You must set the name",
		}
		error = False
		for k,v in validation.iteritems():
			if getattr(args, k) is None:
				self.err(v)
				error = True

		if error:
			parser.print_help()
			return

		image = self._talus_client.image_create(
			image_name				= args.name,
			base_image_id_or_name	= args.base,
			os_id					= args.os,
			desc					= args.desc,
			tags					= args.tags,
			vagrantfile				= vagrantfile_contents,
			user_interaction		= args.interactive
		)

		self._wait_for_image(image, args.interactive)
Example #14
0
    def do_export(self, args):
        """Export crash information to the target directory. Crashes are identified using
		git-like syntax, ids, and/or search queries, as with the info commands:

			crash export --tags IE +2

		The above command will export the 2nd most recent crash (+2) that belongs to you and
		contains the tag "IE".

		By default crashes will be saved into the current working directory. Use the --dest
		argument to specify a different output directory:

			crash export +1 --all --tags adobe --dest adobe_crashes

		The more complicated example below will search among all crashes (--all, vs only
		those tagged with your username) for ones that have an exploitability category of
		EXPLOITABLE and crashing module of libxml. The second crash (+2) will be chosen
		after sorting by data.registers.eax

			crash export --all --exploitability EXPLOITABLE --crashing_module libxml --sort data.registers.eax +2
		"""
        if args.strip() == "":
            raise errors.TalusApiError(
                "you must provide a name/id/git-thing of a crash to export it")

        parts = shlex.split(args)

        leftover = []
        crash_id_or_name = None
        search = self._search_terms(
            parts,
            out_leftover=leftover,
            no_hex_keys=["hash_major", "hash_minor", "hash"])

        root_level_items = [
            "created", "tags", "job", "tool", "$where", "sort", "num", "dest"
        ]
        new_search = {}
        new_search["type"] = "crash"
        for k, v in search.iteritems():
            if k in root_level_items:
                new_search[k] = v
            else:
                new_search["data." + k] = v
        search = new_search

        dest_dir = search.setdefault("dest", os.getcwd())
        dest_dir = os.path.expanduser(dest_dir)
        del search["dest"]

        if len(leftover) > 0:
            crash_id_or_name = leftover[0]

        crash = self._resolve_one_model(crash_id_or_name,
                                        Result,
                                        search,
                                        sort="-created")
        if crash is None:
            raise errors.TalusApiError(
                "could not find a crash with that id/search")

        self.ok("exporting crash {} from job {}".format(
            crash.id, self._nice_name(crash, "job"), crash.tags))

        first_num = int(crash.data["hash_major"], 16)
        second_num = int(crash.data["hash_minor"], 16)
        adj = utils.ADJECTIVES[first_num % len(utils.ADJECTIVES)]
        noun = utils.NOUNS[second_num % len(utils.NOUNS)]

        dest_name = "{}_{}_{}".format(adj, noun, crash.id)
        dest_path = os.path.join(dest_dir, dest_name)
        self.ok("saving to {}".format(dest_path))

        if os.path.exists(dest_path):
            self.warn(
                "export path ({}) already exists! not gonna overwrite it, bailing"
                .format(dest_path))
            return

        os.makedirs(dest_path)

        file_path = os.path.join(dest_path, "crash.json")
        self.out(file_path)
        with open(file_path, "wb") as f:
            f.write(
                json.dumps(crash._filtered_fields(),
                           indent=4,
                           separators=(",", ": ")).encode("utf-8"))

        file_path = os.path.join(dest_path, "crash.txt")
        self.out(file_path)
        with open(file_path, "wb") as f:
            txt_info = self.do_info("",
                                    return_string=True,
                                    crash=crash,
                                    show_details=True)
            txt_info = utils.strip_color(txt_info)
            f.write(txt_info.encode("utf-8"))

        for file_id in crash.data.setdefault("repro", []):
            fname, data = self._talus_client.corpus_get(file_id)
            if fname is None:
                fname = file_id

            file_path = os.path.join(dest_path, "repro", fname)
            if not os.path.exists(os.path.dirname(file_path)):
                os.makedirs(os.path.dirname(file_path))

            self.out(file_path)
            with open(file_path, "wb") as f:
                f.write(data.encode("utf-8"))

        self.ok("done exporting crash")
Example #15
0
    def do_info(self,
                args,
                return_string=False,
                crash=None,
                show_details=False):
        """List detailed information about the crash.

		Git-like syntax can also be used here to refer to the most recently created
		crash result. E.g. the command below will show info about the 2nd most recent crash:

			crash info +2

		Search information can also be used. If git-like syntax is omitted, only
		the first entry returned from the database will be displayed.

			crash info --all --registers.eip 0x41414141 --sort registers.eax +1

		The example above will show information about the crash with the lowest eax value
		(+2 would show the 2nd lowest) that has an eip 0f 0x41414141.  Omitting --all will
		cause the search to be performed only among _your_ crashes.

		To view _all_ of the details about a crash, add the --details flag.
		"""
        if crash is None:
            if args.strip() == "":
                raise errors.TalusApiError(
                    "you must provide a name/id/git-thing of a crash to show info about it"
                )

            parts = shlex.split(args)

            if "--details" in parts:
                parts.remove("--details")
                show_details = True

            leftover = []
            crash_id_or_name = None
            search = self._search_terms(
                parts,
                out_leftover=leftover,
                no_hex_keys=["hash_major", "hash_minor", "hash"])

            root_level_items = [
                "created", "tags", "job", "tool", "$where", "sort", "num"
            ]
            new_search = {}
            new_search["type"] = "crash"
            for k, v in search.iteritems():
                if k in root_level_items:
                    new_search[k] = v
                else:
                    new_search["data." + k] = v
            search = new_search

            if len(leftover) > 0:
                crash_id_or_name = leftover[0]

            crash = self._resolve_one_model(crash_id_or_name,
                                            Result,
                                            search,
                                            sort="-created")
            if crash is None:
                raise errors.TalusApiError(
                    "could not find a crash with that id/search")

        crashing_instr = None
        asm = crash.data.setdefault("disassembly", ["?"])
        for x in asm:
            if "->" in x:
                match = re.match(r'^-+>(.*$)', x)
                crashing_instr = match.group(1).strip()
        # if we don't find the arrow, we'll say it's the last instruction in the
        # list
        if crashing_instr is None:
            crashing_instr = x

        crashing_instr = re.sub(r'^([a-f0-9]+\s)*(.*)$', '\\2',
                                crashing_instr).strip()
        crashing_instr = re.sub(r'\s+', " ", crashing_instr)

        colors = deque([
            colorama.Fore.MAGENTA,
            colorama.Fore.CYAN,
            colorama.Fore.YELLOW,
            colorama.Fore.GREEN,
            colorama.Fore.BLUE,
            colorama.Fore.RED,
        ])

        reg_colors = {}
        reg_rows = []
        reg_rows_no_color = []
        registers = crash.data.setdefault("registers", {})
        for reg, val in registers.iteritems():
            reg = reg.lower()
            color = colors.popleft()
            reg_colors[reg] = color
            reg_rows.append(
                [reg, color + "{:8x}".format(val) + colorama.Style.RESET_ALL])
            reg_rows_no_color.append([reg, "{:8x}".format(val)])
            colors.append(color)

        split = int(math.ceil(len(reg_rows) / 2.0))
        table1 = tabulate(reg_rows[:split]).split("\n")
        table1_no_color = tabulate(reg_rows_no_color[:split]).split("\n")
        table2 = tabulate(reg_rows[split:]).split("\n")

        longest_t1 = max(len(x) for x in table1_no_color)

        if len(table2) == 0:
            reg_lines = table1
        else:
            reg_lines = []
            for x in xrange(len(table1)):
                if x >= len(table2):
                    reg_lines.append(table1[x])
                else:
                    fmt_string = "{:" + str(longest_t1) + "}  |  {}"
                    reg_lines.append(fmt_string.format(table1[x], table2[x]))

        for reg, color in reg_colors.iteritems():
            crashing_instr = re.sub(r"\b" + reg + r"\b",
                                    color + reg + colorama.Style.RESET_ALL,
                                    crashing_instr)

        indent = "                  "

        arrow = ""
        asm_text = crash.data.setdefault("disassembly", [])
        for line in asm_text:
            if "->" in line:
                arrow = line.split()[0]

        asm_rows = []
        asm_rows_no_color = []
        arrow_indent = " " * len(arrow)
        for line in crash.data.setdefault("disassembly", []):
            line = line.strip()
            line = re.sub(r'\s+', " ", line)
            if not line.startswith(arrow):
                line = " " * len(arrow) + line

            line_no_color = line
            for reg, color in reg_colors.iteritems():
                line = re.sub(r"\b" + reg + r"\b",
                              color + reg + colorama.Style.RESET_ALL, line)

            has_arrow = (arrow in line)
            line = line.replace(arrow, "")
            line_no_color = line_no_color.replace(arrow, "")

            match = re.match(r'^\s+([a-f0-9]+)\s+([a-f0-9]+)\s+(.*)$', line)
            no_color_match = re.match(r'^\s+([a-f0-9]+)\s+([a-f0-9]+)\s+(.*)$',
                                      line_no_color)
            if match is None:
                match2 = re.match(r'^\s+([a-f0-9]+)\s+(.*)$', line)
                no_color_match2 = re.match(r'^\s+([a-f0-9]+)\s+(.*)$',
                                           line_no_color)
                if match2 is None:
                    asm_rows.append(["", "", "", line])
                    asm_rows_no_color.append(["", "", "", line_no_color])
                else:
                    asm_rows.append([
                        "-->" if has_arrow else "", "",
                        match2.group(1),
                        match2.group(2)
                    ])
                    asm_rows_no_color.append([
                        "-->" if has_arrow else "", "",
                        no_color_match2.group(1),
                        no_color_match2.group(2)
                    ])
            else:
                asm_rows.append([
                    "-->" if has_arrow else "",
                    match.group(1),
                    match.group(2),
                    match.group(3)
                ])
                asm_rows_no_color.append([
                    "-->" if has_arrow else "",
                    no_color_match.group(1),
                    no_color_match.group(2),
                    no_color_match.group(3)
                ])

        table1 = asm_lines = tabulate(asm_rows).split("\n")
        table1_no_color = tabulate(asm_rows_no_color).split("\n")
        table2 = reg_lines

        longest_t1 = max(len(x) for x in table1_no_color)
        asm_and_regs = []

        if len(table2) == 0:
            asm_and_regs = table1
        else:
            asm_and_regs = []
            for x in xrange(len(table1)):
                if x >= len(table2):
                    asm_and_regs.append(table1[x])
                else:
                    no_color_diff = len(table1[x]) - len(table1_no_color[x])
                    fmt_string = "{:" + str(longest_t1 +
                                            no_color_diff) + "}  |  {}"
                    asm_and_regs.append(fmt_string.format(
                        table1[x], table2[x]))

        details = ""
        if show_details:
            if isinstance(crash.data.setdefault("backtrace", ""), list):
                crash.data["backtrace"] = "\n".join(crash.data["backtrace"])

            detail_indent = " " * 4

            details += """
Stack: \n{stack}
Loaded Modules: \n{loaded_mods}
Backtrace: \n{backtrace}
Exploitability Details: \n{exploit_details}
			""".format(
                stack="\n".join(
                    detail_indent + x
                    for x in crash.data.setdefault("stack", "").split("\n")),
                loaded_mods="\n".join(detail_indent + x
                                      for x in crash.data.setdefault(
                                          "loaded_modules", "").split("\n")),
                backtrace="\n".join(detail_indent + x
                                    for x in crash.data.setdefault(
                                        "backtrace", "").split("\n")),
                exploit_details="\n".join(
                    detail_indent + x for x in crash.data.setdefault(
                        "exploitability_details", "").split("\n")),
            )

        res = """
              ID: {id}
            Tags: {tags}
             Job: {job}
  Exploitability: {expl}
Hash Major/Minor: {hash_major} {hash_minor}
     Crash Instr: {crash_instr}
    Crash Module: {crash_module}
  Exception Code: {exception_code:8x}

{asm_and_regs}{details}
		""".format(
            id=crash.id,
            tags=",".join(crash.tags),
            job=self._nice_name(crash, "job"),
            expl=crash.data.setdefault("exploitability", "None"),
            hash_major=crash.data.setdefault("hash_major", "None"),
            hash_minor=crash.data.setdefault("hash_minor", "None"),
            crash_instr=crashing_instr,
            crash_module=crash.data.setdefault("crash_module", ""),
            exception_code=crash.data.setdefault("exception_code", 0),
            reg_tables="\n".join(indent + x for x in reg_lines),
            asm_and_regs="\n".join("    " + x for x in asm_and_regs),
            details=details,
        )

        if not return_string:
            print(res)
        else:
            return res
Example #16
0
    def _search_terms(self,
                      parts,
                      key_remap=None,
                      user_default_filter=True,
                      out_leftover=None,
                      no_hex_keys=None):
        """Return a dictionary of search terms"""

        if no_hex_keys is None:
            no_hex_keys = []
        search = {}
        key = None
        if key_remap is None:
            key_remap = {}

        key_map = {"status": "status.name"}
        key_map.update(key_remap)
        found_all = False

        for item in parts:
            if key is None:
                if not item.startswith("--"):
                    if out_leftover is not None:
                        out_leftover.append(item)
                        continue
                    else:
                        raise errors.TalusApiError(
                            "args must be alternating search item/value pairs!"
                        )
                item = item[2:].replace("-", "_")
                key = item
                if key == "all":
                    found_all = True
                    key = None
                    continue

                if key in key_map:
                    key = key_map[key]

                if key.endswith("__type") or key.endswith(".type"):
                    key += "_"

            elif key is not None:
                # hex conversion
                if re.match(r'^0x[0-9a-f]+$', item,
                            re.IGNORECASE) is not None and key.split(
                                "__")[0] not in no_hex_keys:
                    item = int(item, 16)

                if key in search and not isinstance(search[key], list):
                    search[key] = [search[key]]

                if key in search and isinstance(search[key], list):
                    search[key].append(item)
                else:
                    search[key] = item
                self.out("searching for {} = {}".format(key, item))

                # reset this
                key = None

        if user_default_filter and not found_all and self._talus_user is not None:
            # default filter by username tag
            self.out("default filtering by username (searching for tags = {})".
                     format(self._talus_user))
            self.out("use --all to view all models")

            if "tags" in search and not isinstance(search["tags"], list):
                search["tags"] = [search["tags"]]

            if "tags" in search and isinstance(search["tags"], list):
                search["tags"].append(self._talus_user)
            else:
                search["tags"] = self._talus_user

        if out_leftover is not None and key is not None:
            out_leftover.append(key)

        return search