Beispiel #1
0
	def generateLines(self):
		if self.function is None:
			return []

		il = self.function.mlil

		# Set up IL display options
		renderer = DisassemblyTextRenderer(il)
		renderer.settings.set_option(DisassemblyOption.ShowAddress)
		renderer.settings.set_option(DisassemblyOption.ShowVariableTypesWhenAssigned)

		# Sort basic blocks by IL instruction index
		blocks = il.basic_blocks
		blocks.sort(key = lambda block: block.start)

		# Function header
		result = []
		result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderStartLineType,
			self.function, None, 0, DisassemblyTextLine([], self.function.start)))
		result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderLineType,
			self.function, None, 0, DisassemblyTextLine(self.function.type_tokens, self.function.start)))
		result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionHeaderEndLineType,
			self.function, None, 0, DisassemblyTextLine([], self.function.start)))

		# Display IL instructions in order
		lastAddr = self.function.start
		lastBlock = None
		lineIndex = 0
		for block in il:
			if lastBlock is not None:
				# Blank line between basic blocks
				result.append(LinearDisassemblyLine(LinearDisassemblyLineType.CodeDisassemblyLineType,
					self.function, block, 0, DisassemblyTextLine([], lastAddr)))
			for i in block:
				lines, length = renderer.get_disassembly_text(i.instr_index)
				lastAddr = i.address
				lineIndex = 0
				for line in lines:
					result.append(LinearDisassemblyLine(LinearDisassemblyLineType.CodeDisassemblyLineType,
						self.function, block, lineIndex, line))
					lineIndex += 1
			lastBlock = block

		result.append(LinearDisassemblyLine(LinearDisassemblyLineType.FunctionEndLineType,
			self.function, lastBlock, lineIndex, DisassemblyTextLine([], lastAddr)))

		return result
    def generateLines(self):
        if self.function is None:
            return []

        mlil = self.function.mlil

        # Set up IL display options
        renderer = DisassemblyTextRenderer(mlil)
        # renderer.settings.set_option(DisassemblyOption.ShowAddress)
        renderer.settings.set_option(
            DisassemblyOption.ShowVariableTypesWhenAssigned)

        ast = MediumLevelILAst(mlil)
        ast.generate()

        # Function header
        result = []
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderStartLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine([], self.function.start),
            ))
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine(self.function.type_tokens,
                                    self.function.start),
            ))
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderEndLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine([], self.function.start),
            ))

        line_index = 0
        for il in ast.root.block:
            if (il.instr_index
                    == ast.root.block[-1].instr_index) and il.operation in (
                        MediumLevelILOperation.MLIL_IF,
                        MediumLevelILOperation.MLIL_JUMP_TO,
                        MediumLevelILOperation.MLIL_GOTO,
                        MediumLevelILOperation.MLIL_NORET,
                    ):
                continue

            il_lines, _ = renderer.get_disassembly_text(il.instr_index)
            for line in il_lines:
                result.append(
                    LinearDisassemblyLine(
                        LinearDisassemblyLineType.CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        line,
                    ))
                line_index += 1

        to_visit = [(n, 0) for header, n in sorted(
            ast._regions.items(),
            key=cmp_to_key(lambda i, j: 1 if ast.reaching_conditions.get(
                (i[0], j[0])) is None else 1 if i.start > j.start else -1),
            reverse=True)]

        prev_indent = 0
        indent = 0
        last_il = il
        use_else_condition = False
        while to_visit:
            current_node, indent = to_visit.pop()

            if indent < prev_indent:
                for i in range(prev_indent - 4, indent - 4, -4):
                    result.append(
                        LinearDisassemblyLine(
                            LinearDisassemblyLineType.CodeDisassemblyLineType,
                            self.function,
                            last_il.il_basic_block,
                            line_index,
                            DisassemblyTextLine(
                                [
                                    InstructionTextToken(
                                        InstructionTextTokenType.TextToken,
                                        f'{" "*i}}}',
                                    )
                                ],
                                last_il.address,
                            ),
                        ))

            if isinstance(current_node, MediumLevelILAstSeqNode):
                if isinstance(current_node, MediumLevelILAstElseNode):
                    il_line = DisassemblyTextLine([],
                                                  current_node.header.start)

                    if use_else_condition:
                        il_line.tokens += [
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}'),
                            InstructionTextToken(
                                InstructionTextTokenType.KeywordToken, "if"),
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, " ("),
                            *current_node.condition.tokens,
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, ") {"),
                        ]

                        result.append(
                            LinearDisassemblyLine(
                                LinearDisassemblyLineType.
                                CodeDisassemblyLineType,
                                self.function,
                                il.il_basic_block,
                                line_index,
                                il_line,
                            ))
                    else:
                        il_line.tokens += [
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}'),
                            InstructionTextToken(
                                InstructionTextTokenType.KeywordToken, "else"),
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, " {"),
                        ]

                        result.append(
                            LinearDisassemblyLine(
                                LinearDisassemblyLineType.
                                CodeDisassemblyLineType,
                                self.function,
                                current_node.header,
                                line_index,
                                il_line,
                            ))

                    indent += 4
                    line_index += 1

                if isinstance(current_node.header, MediumLevelILBasicBlock):
                    for il in current_node.header:
                        if (il.instr_index == current_node.header.end -
                                1) and il.operation in (
                                    MediumLevelILOperation.MLIL_IF,
                                    MediumLevelILOperation.MLIL_JUMP_TO,
                                    MediumLevelILOperation.MLIL_GOTO,
                                    MediumLevelILOperation.MLIL_NORET,
                                ):
                            continue

                        il_lines, length = renderer.get_disassembly_text(
                            il.instr_index)

                        for line in il_lines:
                            line.tokens.insert(
                                0,
                                InstructionTextToken(
                                    InstructionTextTokenType.TextToken,
                                    f'{" "*indent}'),
                            )

                            result.append(
                                LinearDisassemblyLine(
                                    LinearDisassemblyLineType.
                                    CodeDisassemblyLineType,
                                    self.function,
                                    il.il_basic_block,
                                    line_index,
                                    line,
                                ))

                elif isinstance(current_node.header,
                                MediumLevelILAstBreakNode):
                    il_line = DisassemblyTextLine([],
                                                  current_node.header.address)

                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken,
                            f'{" "*indent}'),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, "break")
                    ]

                    result.append(
                        LinearDisassemblyLine(
                            LinearDisassemblyLineType.CodeDisassemblyLineType,
                            self.function,
                            il.il_basic_block,
                            line_index,
                            il_line,
                        ))

                line_index += 1

                to_visit += zip(reversed(current_node.children),
                                repeat(indent))

            elif isinstance(current_node, MediumLevelILAstBasicBlockNode):
                for il in current_node.block:
                    if (il.instr_index == current_node.block.end -
                            1) and il.operation in (
                                MediumLevelILOperation.MLIL_IF,
                                MediumLevelILOperation.MLIL_JUMP_TO,
                                MediumLevelILOperation.MLIL_GOTO,
                                MediumLevelILOperation.MLIL_NORET,
                            ):
                        continue

                    il_lines, length = renderer.get_disassembly_text(
                        il.instr_index)

                    for line in il_lines:
                        line.tokens.insert(
                            0,
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}'),
                        )

                        result.append(
                            LinearDisassemblyLine(
                                LinearDisassemblyLineType.
                                CodeDisassemblyLineType,
                                self.function,
                                il.il_basic_block,
                                line_index,
                                line,
                            ))

                        line_index += 1

            elif isinstance(current_node, MediumLevelILBasicBlock):
                for il in current_node:
                    if (il.instr_index
                            == current_node.end - 1) and il.operation in (
                                MediumLevelILOperation.MLIL_IF,
                                MediumLevelILOperation.MLIL_JUMP_TO,
                                MediumLevelILOperation.MLIL_GOTO,
                                MediumLevelILOperation.MLIL_NORET,
                            ):
                        continue

                    il_lines, length = renderer.get_disassembly_text(
                        il.instr_index)

                    for line in il_lines:
                        line.tokens.insert(
                            0,
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}'),
                        )

                        result.append(
                            LinearDisassemblyLine(
                                LinearDisassemblyLineType.
                                CodeDisassemblyLineType,
                                self.function,
                                il.il_basic_block,
                                line_index,
                                line,
                            ))

                        line_index += 1

            elif isinstance(current_node, MediumLevelILAstCondNode):
                use_else_condition = False

                condition = ConstraintVisitor(self.function).visit(
                    current_node.condition)

                il_line = DisassemblyTextLine([], current_node.address)

                if current_node[True] is not None:
                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken,
                            f'{" "*indent}'),
                        InstructionTextToken(
                            InstructionTextTokenType.KeywordToken, "if"),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, " ("),
                        *condition,
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, ") {"),
                    ]

                    result.append(
                        LinearDisassemblyLine(
                            LinearDisassemblyLineType.CodeDisassemblyLineType,
                            self.function,
                            il.il_basic_block,
                            line_index,
                            il_line,
                        ))

                line_index += 1

                to_visit.append((current_node[False], indent))

                if current_node[True] is not None:
                    to_visit.append((current_node[True], indent + 4))
                else:
                    use_else_condition = True

            elif isinstance(current_node, MediumLevelILAstBreakNode):
                il_line = DisassemblyTextLine([], current_node.address)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         "break")
                ]

                result.append(
                    LinearDisassemblyLine(
                        LinearDisassemblyLineType.CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

            elif isinstance(current_node, MediumLevelILAstLoopNode):
                if current_node.condition is not None:
                    condition = ConstraintVisitor(self.function).visit(
                        current_node.condition)

                    il_line = DisassemblyTextLine([],
                                                  current_node.loop[0].address)

                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken,
                            f'{" "*indent}'),
                        InstructionTextToken(
                            InstructionTextTokenType.KeywordToken, "while"),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, " ("),
                        *condition,
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, ") {"),
                    ]

                    result.append(
                        LinearDisassemblyLine(
                            LinearDisassemblyLineType.CodeDisassemblyLineType,
                            self.function,
                            il.il_basic_block,
                            line_index,
                            il_line,
                        ))

                    line_index += 1

                else:
                    raise NotImplementedError("Don't know how to do this yet")

                indent += 4

                for il in current_node.loop:
                    if (il.instr_index
                            == current_node.loop.end - 1) and il.operation in (
                                MediumLevelILOperation.MLIL_IF,
                                MediumLevelILOperation.MLIL_JUMP_TO,
                                MediumLevelILOperation.MLIL_GOTO,
                                MediumLevelILOperation.MLIL_NORET,
                            ):
                        continue

                    il_lines, length = renderer.get_disassembly_text(
                        il.instr_index)

                    for line in il_lines:
                        line.tokens.insert(
                            0,
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}'),
                        )

                        result.append(
                            LinearDisassemblyLine(
                                LinearDisassemblyLineType.
                                CodeDisassemblyLineType,
                                self.function,
                                il.il_basic_block,
                                line_index,
                                line,
                            ))

                        line_index += 1

                to_visit += zip(reversed(current_node.children),
                                repeat(indent))

            elif isinstance(current_node, MediumLevelILAstSwitchNode):
                il_line = DisassemblyTextLine([], current_node.switch.address)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.KeywordToken,
                                         "switch"),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         " ("),
                    *current_node.switch.tokens,
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         ") {"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        LinearDisassemblyLineType.CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

                to_visit += zip(
                    reversed(
                        sorted(current_node.cases.items(),
                               key=lambda i: i[0])),
                    repeat(indent + 4),
                )

            elif isinstance(current_node, tuple):
                il_line = DisassemblyTextLine(
                    [], current_node[1].header.source_block.start)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.OpcodeToken,
                                         "case "),
                    InstructionTextToken(
                        InstructionTextTokenType.IntegerToken,
                        str(current_node[0]),
                        current_node[0],
                    ),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         " {"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        LinearDisassemblyLineType.CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

                to_visit += [(current_node[1], indent + 4)]

            prev_indent = indent
            last_il = il

        if indent != 0:
            for i in range(indent, 0, -4):
                result.append(
                    LinearDisassemblyLine(
                        LinearDisassemblyLineType.CodeDisassemblyLineType,
                        self.function,
                        last_il.il_basic_block,
                        line_index,
                        DisassemblyTextLine(
                            [
                                InstructionTextToken(
                                    InstructionTextTokenType.TextToken,
                                    f'{" "*(i-4)}}}')
                            ],
                            last_il.address,
                        ),
                    ))
                line_index += 1

        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionEndLineType,
                self.function,
                last_il.il_basic_block,
                line_index,
                DisassemblyTextLine([], last_il.instr_index),
            ))

        return result
Beispiel #3
0
    def generateLines(self):
        if self.function is None:
            return []

        if self.function in self.function_cache:
            return self.function_cache[self.function]

        mlil = self.function.mlil

        # Set up IL display options
        renderer = DisassemblyTextRenderer(mlil)
        # renderer.settings.set_option(DisassemblyOption.ShowAddress)
        # renderer.settings.set_option(
        #     DisassemblyOption.ShowVariableTypesWhenAssigned
        # )

        ast = MediumLevelILAst(mlil)
        ast.generate()

        # Function header
        result = []
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderStartLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine([], self.function.start),
            ))
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine(self.function.type_tokens,
                                    self.function.start),
            ))
        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionHeaderEndLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine([], self.function.start),
            ))

        # add variables
        for var in self.function.vars:
            var_line = DisassemblyTextLine([], 0)

            var_line.tokens += var.type.get_tokens_before_name()
            var_line.tokens += [
                InstructionTextToken(InstructionTextTokenType.TextToken, " "),
                InstructionTextToken(
                    InstructionTextTokenType.LocalVariableToken,
                    var.name,
                    var.identifier,
                ),
                InstructionTextToken(InstructionTextTokenType.TextToken, " "),
            ]
            var_line.tokens += var.type.get_tokens_after_name()

            result.append(
                LinearDisassemblyLine(
                    LinearDisassemblyLineType.LocalVariableLineType,
                    self.function,
                    None,
                    0,
                    var_line,
                ))

        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.LocalVariableListEndLineType,
                self.function,
                None,
                0,
                DisassemblyTextLine([], 0),
            ))

        line_index = 0

        to_visit = [(ast.regions[0][1], 0)]

        prev_indent = 0
        indent = 0
        il = self.function.mlil[0]
        last_il = self.function.mlil[0]
        do_while = []
        while to_visit:
            current_node, indent = to_visit.pop()

            if indent < prev_indent:
                for i in range(prev_indent - 4, indent - 4, -4):
                    il_line = DisassemblyTextLine(
                        [
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*i}}}',
                            )
                        ],
                        last_il.address,
                    )

                    if do_while and do_while[-1][0] == i:
                        condition = do_while.pop()[1]
                        il_line.tokens += [
                            InstructionTextToken(
                                InstructionTextTokenType.KeywordToken,
                                " while"),
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, "("),
                            *condition,
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, ")"),
                        ]

                    result.append(
                        LinearDisassemblyLine(
                            _CodeDisassemblyLineType,
                            self.function,
                            last_il.il_basic_block,
                            line_index,
                            il_line,
                        ))

            if current_node.type == "seq":
                to_visit += zip(reversed(current_node.nodes), repeat(indent))

            elif current_node.type == "block":
                for il in current_node.block:
                    if (il.instr_index == current_node.block.end -
                            1) and il.operation in (
                                MediumLevelILOperation.MLIL_IF,
                                MediumLevelILOperation.MLIL_JUMP_TO,
                                MediumLevelILOperation.MLIL_GOTO,
                                MediumLevelILOperation.MLIL_NORET,
                            ):
                        continue

                    il_lines, _ = renderer.get_disassembly_text(il.instr_index)

                    for line in il_lines:

                        new_tokens = TokenVisitor().visit(il)

                        line.tokens = [
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken,
                                f'{" "*indent}',
                            ), *new_tokens
                        ]

                        result.append(
                            LinearDisassemblyLine(
                                _CodeDisassemblyLineType,
                                self.function,
                                il.il_basic_block,
                                line_index,
                                line,
                            ))

                        line_index += 1

            elif current_node.type == "break":
                il_line = DisassemblyTextLine([], current_node.address)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         "break"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

            elif current_node.type == "cond":
                if is_false(current_node.condition):
                    continue

                if current_node[True] is not None:
                    condition = ConstraintVisitor(self.function).visit(
                        current_node.condition)
                elif current_node[False] is not None:
                    condition = ConstraintVisitor(self.function).visit(
                        Not(current_node.condition))

                il_line = DisassemblyTextLine([], current_node.address)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.KeywordToken,
                                         "if"),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         " ("),
                    *condition,
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         ") {"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

                if current_node[False] is not None:
                    to_visit.append((current_node[False], indent + 4))

                    # Append a node that will tell us that the next node is
                    # an else block
                    if current_node[True] is not None:
                        to_visit.append((
                            MediumLevelILAstElseNode(self,
                                                     current_node.address),
                            indent,
                        ))

                if current_node[True] is not None:
                    to_visit.append((current_node[True], indent + 4))

            elif current_node.type == "else":
                il_line = DisassemblyTextLine([], current_node.address)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.KeywordToken,
                                         "else"),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         " {"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

            elif current_node.type == "loop":
                condition = ConstraintVisitor(self.function).visit(
                    current_node.condition)

                il_line = DisassemblyTextLine([], current_node.address)

                il_line.tokens.append(
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'))

                if current_node.loop_type in ("while", "endless"):
                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.KeywordToken, "while"),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, " ("),
                        *condition,
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, ") {"),
                    ]
                elif current_node.loop_type == "dowhile":
                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.KeywordToken, "do"),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, " {"),
                    ]

                    do_while.append((indent, condition))

                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

                to_visit += zip(reversed(current_node.body.nodes),
                                repeat(indent + 4))

            elif current_node.type == "switch":
                il_line = DisassemblyTextLine([], current_node.address)

                condition = ConstraintVisitor(self.function).visit(
                    current_node.switch)

                il_line.tokens += [
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         f'{" "*indent}'),
                    InstructionTextToken(InstructionTextTokenType.KeywordToken,
                                         "switch"),
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         " ("),
                    *condition,
                    InstructionTextToken(InstructionTextTokenType.TextToken,
                                         ") {"),
                ]

                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        il.il_basic_block,
                        line_index,
                        il_line,
                    ))

                line_index += 1

                to_visit += zip(reversed(current_node.cases),
                                repeat(indent + 4))

            elif current_node.type == "case":
                il_line = DisassemblyTextLine([], current_node.address)

                for idx, v in enumerate(current_node.value):
                    il_line.tokens += [
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken,
                            f'{" "*indent}'),
                        InstructionTextToken(
                            InstructionTextTokenType.TextToken, "case "),
                        (InstructionTextToken(
                            InstructionTextTokenType.IntegerToken, str(v), v)
                         if v != 'default' else InstructionTextToken(
                             InstructionTextTokenType.TextToken, v))
                    ]

                    if idx == len(current_node.value) - 1:
                        il_line.tokens.append(
                            InstructionTextToken(
                                InstructionTextTokenType.TextToken, " {"))

                    result.append(
                        LinearDisassemblyLine(
                            _CodeDisassemblyLineType,
                            self.function,
                            il.il_basic_block,
                            line_index,
                            il_line,
                        ))

                    line_index += 1

                    il_line = DisassemblyTextLine([], current_node.address)

                to_visit += zip(reversed(current_node.nodes),
                                repeat(indent + 4))

            prev_indent = indent
            last_il = il

        if indent != 0:
            for i in range(indent, 0, -4):
                result.append(
                    LinearDisassemblyLine(
                        _CodeDisassemblyLineType,
                        self.function,
                        last_il.il_basic_block,
                        line_index,
                        DisassemblyTextLine(
                            [
                                InstructionTextToken(
                                    InstructionTextTokenType.TextToken,
                                    f'{" "*(i-4)}}}',
                                )
                            ],
                            last_il.address,
                        ),
                    ))
                line_index += 1

        result.append(
            LinearDisassemblyLine(
                LinearDisassemblyLineType.FunctionEndLineType,
                self.function,
                last_il.il_basic_block,
                line_index,
                DisassemblyTextLine([], last_il.instr_index),
            ))

        self.function_cache[self.function] = result

        log_debug("generateLines finished")

        return result