示例#1
0
def gdbmi():
    """
    Inicializa el controlador de gdb
    """
    controller = GdbController([DEBUGGER, KERNEL, "--interpreter=mi3"])
    controller.write("target remote :1234")
    return controller
示例#2
0
    def test_controller(self):
        """Build a simple C program, then run it with GdbController and verify the output is parsed
        as expected"""
        SAMPLE_C_CODE_DIR = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), 'sample_c_app')
        SAMPLE_C_BINARY = os.path.join(SAMPLE_C_CODE_DIR, 'a.out')
        # Build C program
        subprocess.check_output(["make", "-C", SAMPLE_C_CODE_DIR, '--quiet'])

        # Initialize object that manages gdb subprocess
        gdbmi = GdbController()

        # Load the binary and its symbols in the gdb subprocess
        responses = gdbmi.write('-file-exec-and-symbols %s' % SAMPLE_C_BINARY,
                                timeout_sec=2)

        # Verify output was parsed into a list of responses
        assert (len(responses) != 0)
        response = responses[0]
        assert (set(response.keys()) == set(
            ['message', 'type', 'payload', 'stream', 'token']))
        assert (response['message'] == 'thread-group-added')
        assert (response['type'] == 'notify')
        assert (response['payload'] == {'id': 'i1'})
        assert (response['stream'] == 'stdout')
        assert (response['token'] == None)

        responses = gdbmi.write(
            ['-file-list-exec-source-files', '-break-insert main'])
        assert (len(responses) != 0)

        # Close gdb subprocess
        responses = gdbmi.exit()
        assert (responses is None)
        assert (gdbmi.gdb_process is None)
示例#3
0
    def test_controller(self):
        """Build a simple C program, then run it with GdbController and verify the output is parsed
        as expected"""

        # Initialize object that manages gdb subprocess
        gdbmi = GdbController()

        c_hello_world_binary = self._get_c_program("hello", "pygdbmiapp.a")

        if USING_WINDOWS:
            c_hello_world_binary = c_hello_world_binary.replace("\\", "/")
        # Load the binary and its symbols in the gdb subprocess
        responses = gdbmi.write("-file-exec-and-symbols %s" %
                                c_hello_world_binary,
                                timeout_sec=1)

        # Verify output was parsed into a list of responses
        assert len(responses) != 0
        response = responses[0]
        assert set(response.keys()) == {
            "message", "type", "payload", "stream", "token"
        }

        assert response["message"] == "thread-group-added"
        assert response["type"] == "notify"
        assert response["payload"] == {"id": "i1"}
        assert response["stream"] == "stdout"
        assert response["token"] is None

        responses = gdbmi.write(
            ["-file-list-exec-source-files", "-break-insert main"],
            timeout_sec=3)
        assert len(responses) != 0

        responses = gdbmi.write(["-exec-run", "-exec-continue"], timeout_sec=3)

        # Test GdbTimeoutError exception
        got_timeout_exception = False
        try:
            gdbmi.get_gdb_response(timeout_sec=0)
        except GdbTimeoutError:
            got_timeout_exception = True
        assert got_timeout_exception is True

        # Close gdb subprocess
        responses = gdbmi.exit()
        assert responses is None
        assert gdbmi.gdb_process is None

        # Test ValueError exception
        self.assertRaises(ValueError, gdbmi.write,
                          "-file-exec-and-symbols %s" % c_hello_world_binary)

        # Respawn and test signal handling
        gdbmi.spawn_new_gdb_subprocess()
        responses = gdbmi.write("-file-exec-and-symbols %s" %
                                c_hello_world_binary,
                                timeout_sec=1)
        responses = gdbmi.write(["-break-insert main", "-exec-run"])
示例#4
0
class RRController:
    def __init__(self, binary_path: str, trace: List[Instruction]) -> None:
        self.binary_path = binary_path
        self.trace = trace
        self.rr = GdbController(gdb_path=DEFAULT_RR_PATH,
                                gdb_args=[binary_path],
                                rr=True)
        self.current_index = 0

    def eval_expression(self, expr: str) -> None:
        res = self.rr.write("-data-evaluate-expression %s" % expr,
                            timeout_sec=99999)
        print(res)

    def write_request(self,
                      req: str,
                      get_resp: bool = True,
                      **kwargs: Any) -> List[Dict[str, Any]]:
        timeout_sec = kwargs.pop("timeout_sec", 10)
        kwargs["read_response"] = False
        self.rr.write(req, timeout_sec=timeout_sec, **kwargs)
        resp = []  # type: List[Dict[str, Any]]
        if get_resp:
            while True:
                try:
                    resp += self.rr.get_gdb_response()
                except Exception:
                    break
        return resp

    def count_occurence(self, idx: int) -> int:
        """Count # of addr -> target in trace"""
        instruction = self.trace[idx]
        addr = instruction.ip
        cnt = 0
        step = 1 if idx > self.current_index else -1
        for i in range(self.current_index, idx, step):
            e = self.trace[i]
            if e.ip == addr:
                cnt += 1
        return cnt

    def run_until(self, idx: int) -> None:
        instruction = self.trace[idx]
        addr = instruction.ip
        n = self.count_occurence(idx)
        cont_ins = "c" if idx > self.current_index else "reverse-cont"
        self.write_request("b *{}".format(hex(addr)),
                           get_resp=False,
                           timeout_sec=100)
        self.write_request("{} {}".format(cont_ins, n),
                           get_resp=False,
                           timeout_sec=10000)
        self.write_request("clear *{}".format(hex(addr)),
                           get_resp=False,
                           timeout_sec=100)
示例#5
0
class gdb_wrapper_x86_64(gdb_wrapper):
    def __init__(self, port: int = None, file: str = None):
        self.gdb_ctrl = GdbController(
            ["gdb-multiarch", "-q", "--interpreter=mi"])
        self.gdb_ctrl.write("set architecture i386:x86_64")
        self._registers = {'r{}'.format(i) for i in range(8, 16)}
        self._registers.update({
            'rax', 'rdi', 'rsi', 'rdx', 'rcx', 'rbx', 'rsp', 'rbp', 'rip',
            'eflags'
        })
        # self._registers.update({'eax', 'edi', 'esi', 'edx', 'ecx', 'ebx', 'esp', 'ebp', 'eip'})
        self._flags_name = 'eflags'
        self._flag_to_pos = {
            'CF': [0],
            'PF': [2],
            'AF': [4],
            'ZF': [6],
            'SF': [7],
            'TF': [8],
            'IF': [9],
            'DF': [10],
            'OF': [11],
            'IOPL': [11, 12],
            'NT': [14],
            'RF': [16],
            'VM': [17],
            'AC': [18],
            'VIF': [19],
            'VIP': [20],
            'ID': [21]
        }

        super().__init__(port, file)

    @gdb_wrapper.no_response()
    def get_flags(self, timeout_sec: int = DEFAULT_GDB_TIMEOUT_SEC):
        log = self.gdb_ctrl.write("print ${}".format(self._flags_name),
                                  timeout_sec)
        _, _, values = self._parse_log(log,
                                       'console')['payload'].partition(' = ')
        result = {}
        all_flags = values.rstrip('\\n').strip('][').split()
        for flag_value in all_flags:
            flag_name, _, value = flag_value.partition('=')
            if value == '':
                value = 1
            result[flag_name] = value
        for flag_name in self._flag_to_pos:
            if flag_name not in result:
                result[flag_name] = 0
        return result
示例#6
0
文件: __init__.py 项目: Airtnp/hase
class RRController(object):
    def __init__(self, binary_path, trace):
        self.binary_path = binary_path
        self.trace = trace
        self.rr = GdbController(
            gdb_path=DEFAULT_RR_PATH,
            gdb_args=[binary_path],
            rr=True,
        )
        self.current_index = 0

    def eval_expression(self, expr):
        # type: (str) -> None
        res = self.rr.write(
            "-data-evaluate-expression %s" % expr, timeout_sec=99999)
        print(res)

    def write_request(self, req, get_resp=True, **kwargs):
        timeout_sec = kwargs.pop('timeout_sec', 10)
        kwargs['read_response'] = False
        self.rr.write(req, timeout_sec=timeout_sec, **kwargs)
        resp = []
        if get_resp:
            while True:
                try:
                    resp += self.rr.get_gdb_response()
                except:
                    break
        return resp

    def count_occurence(self, idx):
        """Count # of addr -> target in trace"""
        event = self.trace[idx]
        addr = event.addr
        cnt = 0
        step = 1 if idx > self.current_index else -1
        for i in range(self.current_index, idx, step):
            e = self.trace[i]
            if e.addr == addr:
                cnt += 1

    def run_until(self, idx):
        event = self.trace[idx]
        addr = event.addr
        n = self.count_occurence(idx)
        cont_ins = 'c' if idx > self.current_index else 'reverse-cont'
        self.write_request('b *{}'.format(hex(addr)), get_resp=False, timeout_sec=100)
        self.write_request('{} {}'.format(cont_ins, n), get_resp=False, timeout_sec=10000)
        self.write_request('clear *{}'.format(hex(addr)), get_resp=False, timeout_sec=100)
示例#7
0
    def test_controller(self):
        """Build a simple C program, then run it with GdbController and verify the output is parsed
        as expected"""

        # Initialize object that manages gdb subprocess
        gdbmi = GdbController()

        c_binary_path = self._get_c_program()
        # Load the binary and its symbols in the gdb subprocess
        responses = gdbmi.write('-file-exec-and-symbols %s' % c_binary_path,
                                timeout_sec=1)

        # Verify output was parsed into a list of responses
        assert (len(responses) != 0)
        response = responses[0]
        assert (set(response.keys()) == set(
            ['message', 'type', 'payload', 'stream', 'token']))
        assert (response['message'] == 'thread-group-added')
        assert (response['type'] == 'notify')
        assert (response['payload'] == {'id': 'i1'})
        assert (response['stream'] == 'stdout')
        assert (response['token'] is None)

        responses = gdbmi.write(
            ['-file-list-exec-source-files', '-break-insert main'])
        assert (len(responses) != 0)

        responses = gdbmi.write(['-exec-run', '-exec-continue'], timeout_sec=3)
        found_match = False
        for r in responses:
            if r.get(
                    'payload', ''
            ) == '  leading spaces should be preserved. So should trailing spaces.  ':
                found_match = True
        assert (found_match is True)

        # Close gdb subprocess
        responses = gdbmi.exit()
        assert (responses is None)
        assert (gdbmi.gdb_process is None)

        # Test NoGdbProcessError exception
        got_no_process_exception = False
        try:
            responses = gdbmi.write('-file-exec-and-symbols %s' %
                                    c_binary_path)
        except NoGdbProcessError:
            got_no_process_exception = True
        assert (got_no_process_exception is True)
示例#8
0
class gdb_wrapper_avr(gdb_wrapper):
    def __init__(self, port: int = None, file: str = None):
        self.gdb_ctrl = GdbController(["avr-gdb", "-q", "--interpreter=mi"])
        self._registers = {'r{}'.format(i) for i in range(32)}
        self._registers.update({'SP', 'PC', 'SREG'})
        self._flags_name = 'SREG'
        self._flag_to_pos = {
            'C': [0],
            'Z': [1],
            'N': [2],
            'V': [3],
            'S': [4],
            'H': [5],
            'T': [6],
            'I': [7]
        }

        super().__init__(port, file)

    @gdb_wrapper.no_response()
    def get_flags(self, timeout_sec: int = DEFAULT_GDB_TIMEOUT_SEC):
        all_flags = ['C', 'Z', 'N', 'V', 'S', 'H', 'T', 'I']
        log = self.gdb_ctrl.write("print ${}".format(self._flags_name),
                                  timeout_sec)
        _, _, values = gdb_wrapper._parse_log(
            log, 'console')['payload'].partition(' = ')

        return gdb_wrapper._parse_flags(int(values.rstrip('\\n')), all_flags)
示例#9
0
def getBackTrack(target, pov, src_list):
    """
    Get back track, returns the last buggy file and line number.
    Arg1: target binary
    Arg2: argument of target binary
    Arg3: src list which is used to filter unrelated files.
    """
    try:
        gdbmi = GdbController()
        response = gdbmi.write('-file-exec-and-symbols %s' % target)
        response = gdbmi.write('run')
        response = gdbmi.write('bt')

        getLastCall(response, src_list)

    except Exception as e:
        print e
示例#10
0
class GDB:
    def __init__(self):
        self.gdbmi = None
        self.timeout = 10
        self.command = ""
        self.opLog = None

    def gdbStart(self, gdbPath):
        #open log file
        logFile = 'copy_to_flash_' + str(
            datetime.now().strftime("%Y-%m-%d_%H:%M:%S")) + '.log'
        self.opLog = open(logFile, 'w+')
        #open gdb
        self.gdbmi = GdbController(gdb_path=gdbPath,
                                   gdb_args=None,
                                   time_to_check_for_additional_output_sec=4.5,
                                   rr=False,
                                   verbose=False)
        #print('started gdb')

    def gdbSendCommand(self, command):
        self.command = command
        if self.gdbmi is None:
            return False
        #send command and get output.
        response = self.gdbmi.write(command, timeout_sec=self.timeout)
        if len(response) == 0:
            return False
        return response

    def gdbClose(self):
        #close gdb
        if self.gdbmi is None:
            return False
        self.gdbmi.send_signal_to_gdb("SIGINT")
        self.gdbmi.send_signal_to_gdb(2)
        self.gdbmi.interrupt_gdb()
        assert self.gdbmi.exit() is None
        assert self.gdbmi.gdb_process is None
        self.opLog.close()
        return True

    def getResponseTypeMsg(self, response):
        TypeMsg = ""
        typeMsgNum = str(response).count("payload")
        #get exact gdb console response.
        for line in range(typeMsgNum):
            if (str(response[line]['type'])) == "console":
                TypeMsg += (str(response[line]['payload']))
        self.opLog.write("The output of " + self.command + " :\n" + TypeMsg +
                         "\n")
        return TypeMsg

    def gdbSendSignal(self, sig):
        if self.gdbmi is None:
            return False
        self.gdbmi.send_signal_to_gdb(sig)
示例#11
0
文件: __init__.py 项目: wadoon/bigdb
    def do_gdb(self, gdb: GdbController, pid: int):
        # -stack-list-locals2
        # ^done, locals=[{name = "r", type = "int", value = "0"}]
        resp = gdb.write("-stack-list-locals 2")
        print(resp)
        locals = resp[0]['payload']['locals']

        for var in locals:
            self.tableModelVariables.emit(pid, var['name'], var['value'])
示例#12
0
class gdb_wrapper_arm(gdb_wrapper):
    def __init__(self, port: int = None, file: str = None):
        self.gdb_ctrl = GdbController(
            ["gdb-multiarch", "-q", "--interpreter=mi"])
        self.gdb_ctrl.write("set architecture arm")
        self._registers = {'r{}'.format(i) for i in range(13)}
        self._registers.update({'sp', 'lr', 'pc', 'cpsr'})
        self._flags_name = 'cpsr'
        self._flag_to_pos = {
            'M': [0, 1, 2, 3, 4],
            'T': [5],
            'F': [6],
            'I': [7],
            'A': [8],
            'E': [9],
            'IT': [25, 26, 10, 11, 12, 13, 14, 15],
            'GE': [16, 17, 18, 19],
            'DNM': [20, 21, 22, 23],
            'J': [24],
            'Q': [27],
            'V': [28],
            'C': [29],
            'Z': [30],
            'N': [31]
        }

        super().__init__(port, file)

    @gdb_wrapper.no_response()
    def get_flags(self, timeout_sec: int = DEFAULT_GDB_TIMEOUT_SEC):
        log = self.gdb_ctrl.write("print ${}".format(self._flags_name),
                                  timeout_sec)
        _, _, values = gdb_wrapper._parse_log(
            log, 'console')['payload'].partition(' = ')

        all_flags = [['M', 0], ['M', 1], ['M', 2],
                     ['M', 3], ['M', 4], 'T', 'F', 'I', 'A', 'E', ['IT', 2],
                     ['IT', 3], ['IT', 4], ['IT', 5], ['IT', 6], ['IT', 7],
                     ['GE', 0], ['GE', 1], ['GE', 2], ['GE', 3], ['DNM', 0],
                     ['DNM', 1], ['DNM', 2], ['DNM', 3], 'J', ['IT', 0],
                     ['IT', 1], 'Q', 'V', 'C', 'Z', 'N']

        return gdb_wrapper._parse_flags(int(values.rstrip('\\n')), all_flags)
示例#13
0
def vul3_32(exe):
    slack = -254
    signal = response = data_address = bss_address = None
    b = []
    test_file = "test_file.bin"

    while signal != 'SIGSEGV':

        slack += 254
        for x in range(1, 255):
            b.extend([x, x, x, x])

        f = open(test_file, "wb")
        f.write(bytes(b))
        f.close()

        gdbmi = GdbController()
        gdbmi.write('file ' + exe)
        gdbmi.write('-break-insert main')
        gdbmi.write('-exec-arguments ' + test_file)
        gdbmi.write('-exec-run')
        response = gdbmi.write('maint info section')
        if data_address is None:
            (data_address, bss_address) = get_addreses(response)
        response = gdbmi.write('-exec-continue')

        if response[-1]['payload']['reason'] == 'signal-received':
            address = response[-1]['payload']['frame']['addr']
            if address[2:4] == address[4:6] or address[6:8] == address[8:]:
                signal = response[-1]['payload']['signal-name']
                # pprint(response)

    address = response[-1]['payload']['frame']['addr']
    length = ((int(address[8:], 16) - 1) + slack) * 4

    if int(address[8:], 16) != int(address[2:4], 16):
        length += 4
        i = 10
        while int(address[i - 2:i], 16) != int(address[2:4], 16):
            length -= 1
            i -= 2
    os.remove(test_file)
    return length, data_address, bss_address
示例#14
0
    class gdb_runner:
        def __init__(self, arch):
            self.arch = arch

        # Method that runs a GDB process, gains control of it through stdin,
        # and attaches it to a specified QEMU process.
        # Arguments:
        #	gdb_exec - full path to gdb executable.
        #	qemu_inst - object of qemu_runner or it's descendant class.
        def run_and_attach(self, gdb_exec, qemu_inst):
            self.gdb_ctrl = GdbController([gdb_exec, "-q", "--interpreter=mi"])
            return self.attach(qemu_inst)

        # Method that attaches a GDB process to a specified QEMU process.
        def attach(self, qemu_inst):
            resp = self.gdb_ctrl.write("file " + qemu_inst.cur_exec)
            resp.extend(
                self.gdb_ctrl.write("target extended-remote localhost:" +
                                    str(qemu_inst.dbg_port)))
            return resp

        # Method that sends a commands to GDB process via stdin.
        # Arguments:
        #	command - string representing command.
        # Return value:
        #	payload list of dictionaries.
        def write(self, command):
            resp = self.gdb_ctrl.write(command)
            if command.strip() == "q":
                self.gdb_ctrl = None
            return resp

        # Method that sends to GDB process following commands:
        # - kill the process being debugged.
        # - exit GDB.
        def exit(self):
            write("kill")
            write("q")

        # Method that tells if GDB process is active.
        def is_active(self):
            return self.gdb_ctrl != None
示例#15
0
def netperf(exe):
    slack = -254
    signal = response = data_address = bss_address = None
    b = []

    while signal != 'SIGSEGV':

        slack += 254

        for x in range(1, 255):
            b.extend([x, x, x, x])

        arguments = "".join(map(chr, b))
        # if(slack * 4 > 7000):

        gdbmi = GdbController()
        gdbmi.write('file vulnerable_binaries/' + exe)
        gdbmi.write('-break-insert main')
        gdbmi.write('-exec-arguments -a \"' + arguments + '\"')
        gdbmi.write('-exec-run')
        response = gdbmi.write('maint info section')
        if data_address is None:
            (data_address, bss_address) = get_addreses(response)
        response = gdbmi.write('-exec-continue')

        if response[-1]['payload']['reason'] == 'signal-received':
            address = response[-1]['payload']['frame']['addr']
            if address[2:4] == address[4:6] or address[6:8] == address[8:]:
                signal = response[-1]['payload']['signal-name']
                # pprint(response)

    address = response[-1]['payload']['frame']['addr']
    length = ((int(address[8:], 16) - 1) + slack) * 4

    if int(address[8:], 16) != int(address[2:4], 16):
        length += 4
        i = 10
        while int(address[i - 2:i], 16) != int(address[2:4], 16):
            length -= 1
            i -= 2
    return length, data_address, bss_address
class ProbeSession(object):
    def __init__(self, port, host_ip="localhost"):
        self.session = GdbController(gdb_path="arm-none-eabi-gdb")
        # Connect to the debug probe
        self.session.write("target remote %s:%s" % (host_ip, port))

    def __del__(self):
        # Stop the running GDB server
        self.session.exit()

    def register_read(self, reg):

        reg = reg.lower()

        if reg not in reg_list:
            raise "Specified register is not valid for this target."

        output = self.session.write("monitor reg %s" % reg)
        assert (output[1]['type'] == 'target')
        value = reg_value.match(output[1]['payload'])['value']
        return int(value, 16)
示例#17
0
文件: bmp.py 项目: samken600/3YP
def connect_to_target(port):
    # open GDB in machine interface mode
    gdbmi = GdbController(
        gdb_path=args.gdb_path,
        gdb_args=["--nx", "--quiet", "--interpreter=mi2", args.file])
    assert gdb_write_and_wait_for_result(gdbmi,
                                         '-target-select extended-remote %s' %
                                         port,
                                         'connecting',
                                         expected_result='connected')
    # set options
    if args.connect_srst:
        gdbmi.write('monitor connect_srst enable', timeout_sec=TIMEOUT)
    if args.tpwr:
        gdbmi.write('monitor tpwr enable', timeout_sec=TIMEOUT)
    # scan for targets
    if not args.jtag:
        print("scanning using SWD...")
        res = gdbmi.write('monitor swdp_scan', timeout_sec=TIMEOUT)
    else:
        print("scanning using JTAG...")
        res = gdbmi.write('monitor jtag_scan', timeout_sec=TIMEOUT)
    targets = detect_targets(gdbmi, res)
    assert len(targets) > 0, "no targets found"
    print("found following targets:")
    for t in targets:
        print("\t%s" % t)
    print("")
    return gdbmi
示例#18
0
def main(verbose=True):
    """Build and debug an application programatically

    For a list of GDB MI commands, see https://www.sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html
    """

    # Build C program
    subprocess.check_output(["make", "-C", SAMPLE_C_CODE_DIR, '--quiet'])

    # Initialize object that manages gdb subprocess
    gdbmi = GdbController(verbose=verbose)

    # Send gdb commands. Gdb machine interface commands are easier to script around,
    # hence the name "machine interface".
    # Responses are automatically printed as they are received if verbose is True.
    # Responses are returned after writing, by default.

    # Load the file
    responses = gdbmi.write('-file-exec-and-symbols %s' % SAMPLE_C_BINARY)
    # Get list of source files used to compile the binary
    responses = gdbmi.write('-file-list-exec-source-files')
    # Add breakpoint
    responses = gdbmi.write('-break-insert main')
    # Run
    responses = gdbmi.write('-exec-run')
    responses = gdbmi.write('-exec-next')
    responses = gdbmi.write('-exec-next')
    responses = gdbmi.write('-exec-continue')

    gdbmi.exit()
示例#19
0
def try_nums(nums):
    numString = arrayToString(nums)

    gdbmi = GdbController()
    gdbmi.write('file bomb', timeout_sec=5)
    gdbmi.write('break explode_bomb', timeout_sec=5)
    gdbmi.write('run', timeout_sec=5)
    time.sleep(1.5)
    gdbmi.interrupt_gdb()
    gdbmi.write('call (void) initialize_phase6()', timeout_sec=5)
    response = gdbmi.write('call (void) phase6("{0}")'.format(numString),
                           timeout_sec=5)
    for mess in response:
        if mess['message'] == 'stopped':
            gdbmi.exit()
            return numString + "is not the value."
    gdbmi.exit()
    return "! " + numString + "is the value!"
示例#20
0
class GDBSimulator:
    def __init__(self) -> None:
        self.file = None
        self.gdb = GdbController()

    def load(self, file: str) -> None:
        if file == self.file:
            return
        self.file = file
        self.restart()
        return self.run(f'file {self.file}')

    def restart(self) -> None:
        self.gdb.spawn_new_gdb_subprocess()

    def run(self, cmd: str):
        return self.gdb.write(cmd)
示例#21
0
class DebugSession():
    def __init__(self, progname):
        self.gdbmi = GdbController()

        resp = self.cmd('-file-exec-and-symbols ' + progname)
        assert "done" in [r['message'] for r in resp]

        resp = self.cmd('-break-insert main')
        assert "done" in [r['message'] for r in resp]

        resp = self.cmd('-exec-run')
        assert "running" in [r['message'] for r in resp]

        print("initialized")

    def cmd(self, cmd):
        ret = self.gdbmi.write(cmd)
        return ret

    def call_func(self, funcstr):

        funcstr = funcstr.replace('"', '\\"')

        resp = self.cmd(f'-data-evaluate-expression "{funcstr}"')

        try:
            if "error" in [r['message'] for r in resp]:
                resp = self.cmd(
                    f'-data-evaluate-expression "(void*){funcstr}"')
        except:
            pass

        result = [item['payload'] for item in resp if item['type'] == 'result']
        ret = result[0]['value']

        if '"' in ret:
            return '"' + ret.split('"')[1] + '"'
        else:
            return ret.split(' ')[0]

        return ret
示例#22
0
class GDBInspector:
    """Wrapper around pygdbmi.gdbcontroller.GdbController."""

    def __init__(self, binary, corefile='core', path=None):
        self._binary = os.path.join(path, binary) if path else binary
        self._corefile = os.path.join(path, corefile) if path else corefile
        self._gdb = None

    async def __aenter__(self):
        await self.connect()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.exit()

    def __getattr__(self, item):
        return getattr(self._gdb, item)

    @as_future
    def connect(self):
        self._gdb = GdbController(gdb_args=self.gdb_args)

    @as_future
    def exit(self):
        return self._gdb.exit()

    @property
    def gdb_args(self):
        args = [self._binary, self._corefile]
        args += REQUIRED_GDB_FLAGS
        return args

    @as_future
    def write(self, *args, **kwargs):
        return self._gdb.write(*args, **kwargs)

    def corefile_exists(self):
        return os.path.isfile(self._corefile)
示例#23
0
def main(verbose=True):
    """Build and debug an application programatically

    For a list of GDB MI commands, see https://www.sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html
    """

    # Build C program
    find_executable(MAKE_CMD)
    if not find_executable(MAKE_CMD):
        print(
            'Could not find executable "%s". Ensure it is installed and on your $PATH.'
            % MAKE_CMD)
        exit(1)
    subprocess.check_output([MAKE_CMD, "-C", SAMPLE_C_CODE_DIR, "--quiet"])

    # Initialize object that manages gdb subprocess
    gdbmi = GdbController(verbose=verbose)

    # Send gdb commands. Gdb machine interface commands are easier to script around,
    # hence the name "machine interface".
    # Responses are automatically printed as they are received if verbose is True.
    # Responses are returned after writing, by default.

    # Load the file
    responses = gdbmi.write("-file-exec-and-symbols %s" % SAMPLE_C_BINARY)
    # Get list of source files used to compile the binary
    responses = gdbmi.write("-file-list-exec-source-files")
    # Add breakpoint
    responses = gdbmi.write("-break-insert main")
    # Run
    responses = gdbmi.write("-exec-run")
    responses = gdbmi.write("-exec-next")
    responses = gdbmi.write("-exec-next")
    responses = gdbmi.write("-exec-continue")  # noqa: F841

    # gdbmi.gdb_process will be None because the gdb subprocess (and its inferior
    # program) will be terminated
    gdbmi.exit()
示例#24
0
文件: __init__.py 项目: wadoon/bigdb
class CodeFrame(Gtk.VBox):
    location: Path
    toolbar: Gtk.Toolbar
    code: GtkSource.Buffer
    _gdb_callback = None
    _gdb_callback_arg: object
    _gdb: GdbController
    _exec_mark: GtkSource.Mark = None

    def __init__(self):
        Gtk.VBox.__init__(self)
        self._gdb = None
        self.toolbar = Gtk.Toolbar()
        self.btnLoad = Gtk.ToolButton(label="Load", stock_id=Gtk.STOCK_OPEN)
        self.btnSave = Gtk.ToolButton(label="Save", stock_id=Gtk.STOCK_SAVE)
        self.toolbar.add(self.btnLoad)
        self.toolbar.add(self.btnSave)

        self.toolbar.add(Gtk.SeparatorToolItem())

        self.btnStart = Gtk.ToolButton(label="(Re)Start",
                                       stock_id=Gtk.STOCK_MEDIA_PLAY)
        self.toolbar.add(self.btnStart)

        self.btnStep = Gtk.ToolButton(label="s",
                                      stock_id=Gtk.STOCK_MEDIA_FORWARD)
        self.toolbar.add(self.btnStep)

        self.btnContinue = Gtk.ToolButton(label="c",
                                          stock_id=Gtk.STOCK_MEDIA_NEXT)
        self.toolbar.add(self.btnContinue)

        self.editor = GtkSource.View(monospace=True,
                                     show_line_numbers=True,
                                     show_line_marks=True,
                                     tab_width=4,
                                     auto_indent=True,
                                     insert_spaces_instead_of_tabs=True,
                                     show_right_margin=True,
                                     smart_backspace=True,
                                     highlight_current_line=True)

        self.code = GtkSource.Buffer(language=get_gtk_language("cpp"))

        self.editor.set_buffer(self.code)

        # register breakpoints
        mark_attributes = GtkSource.MarkAttributes()
        mark_attributes.set_icon_name(Gtk.STOCK_STOP)
        self.editor.set_mark_attributes(CATEGORY_BREAKPOINT, mark_attributes,
                                        1)

        # register exec marker
        mark_attributes = GtkSource.MarkAttributes()
        mark_attributes.set_icon_name(Gtk.STOCK_GO_FORWARD)
        mark_attributes.set_background(Gdk.RGBA(0, 1, 0, 1))
        self.editor.set_mark_attributes(CATEGORY_EXEC_MARKER, mark_attributes,
                                        0)

        self.editor.connect("line-mark-activated", self.on_line_mark)

        self.pack_start(self.toolbar, expand=False, fill=False, padding=0)
        self.pack_start(self.editor, expand=True, fill=True, padding=2)

        self.btnLoad.connect("clicked", self.load_interactive)
        self.btnSave.connect("clicked", self.save_interactive)

        self.btnStart.connect("clicked", self.gdb_run)
        self.btnStep.connect("clicked", self.gdb_step)
        self.btnContinue.connect("clicked", self.gdb_continue)

        self._breakpoints = dict()

    def on_line_mark(self, view, iter, event: Gdk.Event):
        # print(event.get_button().button == Gdk.BUTTON_PRIMARY,
        #      event.get_button(), Gdk.BUTTON_PRIMARY)

        if event.get_button().button == Gdk.BUTTON_PRIMARY:
            line = iter.get_line()
            if line in self._breakpoints:
                self._disable_breakpoint(iter)
            else:
                self._enable_breakpoint(iter)
        elif event.get_button() == Gdk.BUTTON_SECONDARY:
            pass  # TODO Support for SYNC points

    def _disable_breakpoint(self, iter):
        mark = self._breakpoints[iter.get_line()]
        self.code.delete_mark(mark)
        del self._breakpoints[iter.get_line()]

    def _enable_breakpoint(self, iter):
        mark = self.code.create_source_mark(None, CATEGORY_BREAKPOINT, iter)
        mark.set_visible(True)
        self._breakpoints[iter.get_line()] = mark

    def gdb_run(self, *args):
        if self._gdb:
            # TODO ask user
            self._gdb.exit()
            self._gdb = None

        if not self._gdb:  # start new instance
            self._gdb = GdbController(verbose=True)
            self._gdb.write("-file-exec-and-symbols %s" %
                            get_executable_path(self.location))
            responses = self._gdb.write(
                '-file-list-exec-source-files')  # ['files']

            # Lines <-> PC
            # responses = self._gdb.write("-sym-erubbol-list-lines %s" % self.location)

            # Transfer breakpoints
            fil = self.location.name
            for line in self._breakpoints:
                self._gdb.write("-break-insert %s:%d" % (fil, 1 + line))
            self._gdb.write("-break-insert main")

            # Read breakpoints
            # TODO remove breakpoints and display the correct breakpoints from gdb
            self._remove_all_breakpoints()
            response = self._gdb.write("-break-list")
            for breakpoint in response[0]['payload']['BreakpointTable'][
                    'body']:
                line = int(breakpoint['line'])
                iter = self.code.get_iter_at_line(line - 1)
                self._enable_breakpoint(iter)

            # GDB start debugging, should stop on main
            self._gdb.write('-exec-run')
            self._gdb_notify_callback()

    def _remove_all_breakpoints(self):
        for v in self._breakpoints.values():
            self.code.delete_mark(v)
        del self._breakpoints
        self._breakpoints = dict()

    def gdb_step(self, *args):
        if self._gdb:
            self._gdb.write("-exec-step")
            self._gdb_notify_callback()

    def gdb_continue(self, *args):
        if self._gdb:
            self._gdb.write("-exec-continue")
            self._gdb_notify_callback()

    def _gdb_update_exec_mark(self):
        if self._exec_mark is not None:
            self.code.delete_mark(self._exec_mark)
        # get current line
        response = self._gdb.write("-stack-info-frame")
        line = int(response[0]['payload']['frame']['line'])
        print(line)
        self._exec_mark = self.code.create_source_mark(
            NAME_EXEC_MARKER, CATEGORY_EXEC_MARKER,
            self.code.get_iter_at_line(line - 1))

    def _gdb_notify_callback(self):
        self._gdb_update_exec_mark()
        # ^done,frame={level="0",addr="0x00000000004004cb",func="main",file="left.c",fullname="/home/weigl/work/bigdb/left.c",line="17"}
        self._gdb_callback(self._gdb, self._gdb_callback_arg)

        # -stack-list-frames
        # ^done,stack=[frame={level="0",addr="0x0000000000400495",func="f",file="left.c",fullname="/home/weigl/work/bigdb/left.c",line="4"},frame={level="1",addr="0x00000000004004da",func="main",file="left.c",fullname="/home/weigl/work/bigdb/left.c",line="17"}]

    def load_interactive(self, *args):
        dialog = Gtk.FileChooserDialog(
            "Load file", self.get_toplevel(), Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.load(dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")
        dialog.destroy()

    def save_interactive(self, *args):
        print(self.location)
        if self.location:
            self.save()
        else:
            dialog = Gtk.FileChooserDialog(
                "Save file", self.get_toplevel(), Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE_AS,
                 Gtk.ResponseType.OK))
            response = dialog.run()
            if response == Gtk.ResponseType.OK:
                self.location = Path(dialog.get_filename())
                self.save()
            elif response == Gtk.ResponseType.CANCEL:
                print("Cancel clicked")
            dialog.destroy()

    def load(self, filename):
        with open(filename) as fh:
            self.code.set_text(fh.read())
            self.location = Path(filename)
            lang = get_gtk_language(self.location.suffix[1:])
            self.code.set_language(lang)

    def save(self):
        if self.location:
            self.location.write_text(self.code.get_text())
            os.system("(cd %s; make)" % self.location.parent)

    def set_gdb_callback(self, func, arg=None):
        self._gdb_callback = func
        self._gdb_callback_arg = arg
示例#25
0
    def test_controller(self):
        """Build a simple C program, then run it with GdbController and verify the output is parsed
        as expected"""

        # Initialize object that manages gdb subprocess
        gdbmi = GdbController()

        c_hello_world_binary = self._get_c_program("hello", "pygdbmiapp.a")

        if USING_WINDOWS:
            c_hello_world_binary = c_hello_world_binary.replace("\\", "/")
        # Load the binary and its symbols in the gdb subprocess
        responses = gdbmi.write("-file-exec-and-symbols %s" %
                                c_hello_world_binary,
                                timeout_sec=1)

        # Verify output was parsed into a list of responses
        assert len(responses) != 0
        response = responses[0]
        assert set(response.keys()) == {
            "message", "type", "payload", "stream", "token"
        }

        assert response["message"] == "thread-group-added"
        assert response["type"] == "notify"
        assert response["payload"] == {"id": "i1"}
        assert response["stream"] == "stdout"
        assert response["token"] is None

        responses = gdbmi.write(
            ["-file-list-exec-source-files", "-break-insert main"])
        assert len(responses) != 0

        responses = gdbmi.write(["-exec-run", "-exec-continue"], timeout_sec=3)
        found_match = False
        print(responses)
        for r in responses:
            if (r.get(
                    "payload", ""
            ) == "  leading spaces should be preserved. So should trailing spaces.  "
                ):
                found_match = True
        assert found_match is True

        # Test GdbTimeoutError exception
        got_timeout_exception = False
        try:
            gdbmi.get_gdb_response(timeout_sec=0)
        except GdbTimeoutError:
            got_timeout_exception = True
        assert got_timeout_exception is True

        # Close gdb subprocess
        if not USING_WINDOWS:
            # access denied on windows
            gdbmi.send_signal_to_gdb("SIGINT")
            gdbmi.send_signal_to_gdb(2)
            gdbmi.interrupt_gdb()
        responses = gdbmi.exit()
        assert responses is None
        assert gdbmi.gdb_process is None

        # Test NoGdbProcessError exception
        got_no_process_exception = False
        try:
            responses = gdbmi.write("-file-exec-and-symbols %s" %
                                    c_hello_world_binary)
        except NoGdbProcessError:
            got_no_process_exception = True
        assert got_no_process_exception is True

        # Respawn and test signal handling
        gdbmi.spawn_new_gdb_subprocess()
        responses = gdbmi.write("-file-exec-and-symbols %s" %
                                c_hello_world_binary,
                                timeout_sec=1)
        responses = gdbmi.write(["-break-insert main", "-exec-run"])
        if not USING_WINDOWS:
            gdbmi.interrupt_gdb()
            gdbmi.send_signal_to_gdb(2)
            gdbmi.send_signal_to_gdb("sigTeRm")
            try:
                gdbmi.send_signal_to_gdb("sigterms")
                # exception must be raised
                assert False
            except ValueError:
                assert True
        responses = gdbmi.write("-exec-run")
        if not USING_WINDOWS:
            gdbmi.send_signal_to_gdb("sigstop")
示例#26
0
class CrackMe():
    def __init__(self, args=[]):
        self.uid = str(uuid.uuid4())
        # Start gdb process
        gdb_args = (['--nx', '--quiet', '--interpreter=mi2'] +
                    ['--args', './crackme'] + args)

        self.gdbmi = GdbController(gdb_args=gdb_args)
        logging.info('Starting gdb with ' +
                     repr(self.gdbmi.get_subprocess_cmd()))

    def wait_for_resp(self):
        msgs = []
        out = {}

        while True:
            resp = self.gdbmi.get_gdb_response(timeout_sec=4,
                                               raise_error_on_timeout=False)
            msgs += resp

            for m in resp:
                m = to_namespace(m)
                if m.type != 'result':
                    continue
                out['result'] = m.message
                return msgs, out

    def run(self):
        self.gdbmi.write('run', read_response=False)
        return self.process_execution()

    def cont(self):
        self.gdbmi.write('continue', read_response=False)
        return self.process_execution()

    def si(self):
        self.gdbmi.write('si', read_response=False)
        return self.process_execution()

    def ni(self):
        self.gdbmi.write('ni', read_response=False)
        return self.process_execution()

    def breakpoint(self, addr):
        addr = filter_str(addr)
        self.gdbmi.write('break *' + addr, read_response=False)
        msgs, out = self.wait_for_resp()
        return out

    def set(self, arg):
        arg = filter_str(arg)
        self.gdbmi.write('set ' + arg, read_response=False)
        msgs, out = self.wait_for_resp()
        return out

    def disassemble(self, arg):
        arg = filter_str(arg)
        self.gdbmi.write('disassemble ' + arg, read_response=False)
        msgs, out = self.wait_for_resp()
        data = ''
        for m in msgs:
            m = to_namespace(m)
            if m.type == 'console':
                data += m.payload

        data = data.encode('latin-1').decode('unicode_escape')
        out['data'] = data
        return out

    def memory(self, arg):
        arg = filter_str(arg)
        self.gdbmi.write('x/' + arg, read_response=False)
        msgs, out = self.wait_for_resp()
        data = ''
        for m in msgs:
            m = to_namespace(m)
            if m.type == 'console':
                data += m.payload

        data = data.encode('latin-1').decode('unicode_escape')
        out['data'] = data
        return out

    def registers(self):
        self.gdbmi.write('i r', read_response=False)
        msgs, out = self.wait_for_resp()
        data = ''
        for m in msgs:
            m = to_namespace(m)
            if m.type == 'console':
                data += m.payload

        data = data.encode('latin-1').decode('unicode_escape')
        data = data.strip().split('\n')
        regs = {x[0]: x[1] for x in (y.split() for y in data) if len(x) >= 2}
        out['registers'] = regs
        return out

    def process_execution(self):

        run_output = ''
        running = True

        out = {}

        # Loop until execution stops
        while running:
            resp = self.gdbmi.get_gdb_response(timeout_sec=4,
                                               raise_error_on_timeout=False)

            for m in resp:
                m = to_namespace(m)

                # Console output
                if m.type == 'output':
                    run_output += m.payload

                if m.type == 'result' and m.message == 'error':
                    running = False
                    out['stop_reason'] = m.payload.msg

                # Program stopped
                if m.type == 'notify':
                    if m.message == 'stopped':
                        running = False
                        reason = m.payload.reason
                        out['stop_reason'] = reason
                        if reason == 'breakpoint-hit':
                            out['bp_addr'] = m.payload.frame.addr

        out['output'] = run_output

        return out
示例#27
0
class Gdb:
    def __init__(self, gdb_path=None):
        if gdb_path:
            self.gdbmi = GdbController([gdb_path, "--interpreter=mi3"])
        else:
            self.gdbmi = GdbController()

        self.pc = VimSign("", "", 1000, "dbg_pc")
        self.bp_number = None
        self.bp_line = None
        self.result = None

        self.timeout = 3

    def __write(self, cmd):
        return self.gdbmi.write(cmd, timeout_sec=self.timeout)

    def file_and_exec_symbols(self, filepath):
        response = self.__write("-file-exec-and-symbols %s" % (filepath))
        logger.info("Response: " + str(response))
        self.__parse_response(response)

        if not self.result or self.result == "error":
            logger.error("GDB unable to load exec and symbols file: %s" %
                         filepath)
            return

        logger.debug("GDB loaded exec and symbols file: %s" % filepath)

    def remote(self, address):
        response = self.__write("-target-select remote %s" % (address))
        self.__parse_response(response)

        if not self.result or self.result == "error":
            logger.error("GDB unable to target remote to %s" % (address))
            return

        logger.debug("GDB connect to remote %s" % (address))

    def load(self):
        response = self.__write("-target-download")
        self.__parse_response(response)

        if self.result and self.result == "error":
            logger.error("GDB unable to do target download")
            return

    def insert_bp(self, location):
        logger.info("Inserting breakpoint @location: " + location)
        response = self.__write("-break-insert %s" % (location))
        self.__parse_response(response)

        if not self.result or self.result == "error":
            return False

        return True

    def delete_bp(self, number):
        logger.info("Deleting breakpoint: " + number)
        response = self.__write("-break-delete %s" % (number))
        self.__parse_response(response)

    def go(self):
        response = self.__write("-exec-continue")
        self.__parse_response(response)

        logger.info("Continue")

    def pause(self):
        #self.gdbmi.interrupt_gdb()
        self.__write("-exec-interrupt --all")
        response = self.gdbmi.get_gdb_response(timeout_sec=self.timeout)
        self.__parse_response(response)
        logger.info("Pause")

    def step(self):
        response = self.__write("-exec-step")
        self.__parse_response(response)

        logger.info("Step")

    def __parse_response(self, response):
        global vim

        unused = []
        self.result = None
        self.bp_number = None
        self.bp_line = None

        for r in response:
            if r["type"] == "notify":
                if r["message"] == "stopped":
                    p = r["payload"]

                    if 'frame' in p:
                        self.pc.filepath = p["frame"].get("fullname", None)
                        self.pc.line = p["frame"].get("line", None)

                        if self.pc.filepath and self.pc.line:
                            # open file and move cursor on line
                            vim.execute(":e %s" % (self.pc.filepath))
                            vim.execute(":%s" % (self.pc.line))
                            self.pc.place()

                    if "reason" in p and p["reason"] == "signal-received":
                        vim.echo("GDB: Segmentation fault")
                        pass

                elif r["message"] == "library-loaded":
                    libinfo = r["payload"]
                    logger.debug("Gdb: library loaded: %s" %
                                 (libinfo["target-name"]))

                elif r["message"] == "library-unloaded":
                    libinfo = r["payload"]
                    logger.debug("Gdb: library unloaded: %s" %
                                 (libinfo["target-name"]))

                elif r["message"] in [
                        "thread-group-exited", "thread-group-started",
                        "thread-group-added", "thread-created",
                        "thread-exited", "running", "breakpoint-modified"
                ]:  # TODO: treat this?
                    pass

                else:
                    unused.append(r)

            elif r["type"] == "log":
                logger.debug("GDB: %s" % (r["payload"]))

            elif r["type"] == "result":
                self.result = r["message"]

                if r["payload"] and "bkpt" in r["payload"]:
                    self.bp_number = r["payload"]["bkpt"].get("number", None)
                    self.bp_line = r["payload"]["bkpt"].get("line", None)

            elif r["type"] == "console":
                # ignore cosole output for now
                pass

            elif r["type"] == "output":
                if r["stream"] == "stdout":
                    logger.info("%s" % (r["payload"]))

            else:
                unused.append(r)

        if unused:
            logger.debug("From GDB - not treated:\n" + pprint.pformat(unused))
示例#28
0
from pygdbmi.gdbcontroller import GdbController

#
# Globals
#

DIRNAME = os.path.dirname(os.path.realpath(__file__))
RE_MATCH_ADDY = re.compile(r'0x[0-9a-fA-F]+')
SORTARR_PIE_OFF = 0xdb9

#
# Init GDB
#

gdbmi = GdbController()
gdbmi.write('set cwd ./bin')
gdbmi.write('-file-exec-file ./bin/amicomputable')
gdbmi.write('set disassembly-flavor intel')
gdbmi.write('set environment LD_PRELOAD %s/quick_sort.so' % DIRNAME)
gdbmi.write('run')

print("The PIE offset of the sorting function is: %s" % hex(SORTARR_PIE_OFF))

#
# Search the sort array function
# Cf. Writeup (SOON)
#

sleep(0.5)
gdbmi.send_signal_to_gdb('SIGINT')
gdbmi.interrupt_gdb()
示例#29
0
文件: gdbioctl.py 项目: ufwt/HIAFuzz
def main():
    parser = argparse.ArgumentParser()
    # Ex: python3 gdbioctl.py -v /workspace/difuze/AndroidKernels/kindle_fire_7/WORKSPACE_DIR/out2/vmlinux -f /workspace/difuze/AndroidKernels/kindle_fire_7/WORKSPACE_DIR/out/kindle7_device_ioctl.txt
    # Ex: python3 gdbioctl.py -v /workspace/difuze/AndroidKernels/kindle_fire_7/WORKSPACE_DIR/out2/vmlinux -f /workspace/difuze/AndroidKernels/kindle_fire_7/WORKSPACE_DIR/out/kindle7_device_ioctl.txt
    #parser.add_argument('-o', action='store', dest='ioctl_out', help='Destination directory where all the generated interface should be stored.')
    parser.add_argument(
        '-v',
        action='store',
        dest='vmlinux',
        help=
        'Path of the vmlinux image. The recovered ioctls are stored in this folder.'
    )
    parser.add_argument(
        '-f',
        action='store',
        dest='device_ioctl_file',
        help=
        'The file that conations ioctl and corresponding device file names, Ex: /dev/alarm alarm_ioctl.'
    )
    olddir = os.getcwd()

    parsed_args = parser.parse_args()
    print('%s:%s' % (parsed_args.device_ioctl_file, 5))
    #Before make vmlinux, these steps should be taken.
    '''
    for f in `find . -name Makefile`; do sed -i "s/-g /-g3 /g" $f; done
    for f in `find . -name Makefile`; do sed -i "s/-g$/-g3/g" $f; done
    With make, add this CONFIG_DEBUG_SECTION_MISMATCH=y flag to xxxdeconfig.
    '''
    #Add flag: -fno-inline-functions-called-once

    os.chdir(os.path.dirname(parsed_args.vmlinux))
    outdir = os.path.join(os.path.dirname(parsed_args.vmlinux),
                          'ioctl_finder_out')
    outdir2 = os.path.join(os.path.dirname(parsed_args.vmlinux),
                           'ioctl_preprocessed_out')

    if not os.path.exists(outdir):
        os.mkdir(outdir)
    if not os.path.exists(outdir2):
        os.mkdir(outdir2)

    ioctl_set = []
    #ff = open('/workspace/difuze/AndroidKernels/huawei/mate9/fuben/Code_Opensource/out/ioctls', 'r')
    with open(parsed_args.device_ioctl_file, 'r') as ff:
        ioctl_set = [x.strip() for x in ff.readlines()]

    device_dict = {}
    ioctl_list = []
    if ' ' in ioctl_set[0]:  # Contains devname
        for device_ioctl in ioctl_set:
            device_name, ioctl_name = device_ioctl.split(' ')
            device_dict[ioctl_name] = device_name
            ioctl_list.append(ioctl_name)

        ioctl_set = set(ioctl_list)
        print(device_dict)

    if DEBUG:
        ioctl_set.clear()
        ioctl_set.append('main')
    print(ioctl_set)

    #for aioctl in ioctl_set:
    for aioctl, device_name in device_dict.items():
        print('handling %s' % aioctl)
        ioctl_set.remove(aioctl)
        gdbmi = GdbController()
        response = gdbmi.write('file %s' % parsed_args.vmlinux)
        sourcefile_line_dict = get_line_file_for_ioctl_function_from_gdb(
            gdbmi, aioctl, allow_multi=True)
        item_count = 0
        for sourcefile, line in sourcefile_line_dict.items():
            if sourcefile == '':
                continue
            #if sourcefile[0] != '/':
            #    sourcefile = '/workspace/difuze/dwarf/test/'+sourcefile
            print('%s:%d' % (sourcefile, line))
            cmds_vars = handle_subprogram(gdbmi,
                                          source_name=sourcefile,
                                          decl_line=line,
                                          function_name=aioctl,
                                          depth=0,
                                          list_subprograms=[])
            #print(cmds_vars)
            cmdstypes, restruct = handle_BEGINTYPE_ENDTYPE(gdbmi, cmds_vars)

            if restruct is not None:
                if item_count == 0:
                    processed_filename = os.path.join(outdir2,
                                                      aioctl + '.processed')
                    txt_filename = os.path.join(outdir, aioctl + '.txt')
                else:
                    processed_filename = os.path.join(
                        outdir2, aioctl + str(item_count) + '.processed')
                    txt_filename = os.path.join(
                        outdir, aioctl + str(item_count) + '.txt')

                with open(processed_filename, 'w') as f:
                    f.write(restruct)
                    print(processed_filename + ':1')
            if cmdstypes is not None:
                with open(txt_filename, 'w') as f:
                    f.write('O yeah...\n[+] Provided Function Name: %s\n' %
                            aioctl)
                    if device_dict == {}:
                        f.write('Device Name: tododevname\n')
                    else:
                        f.write('Device Name: %s\n' % device_dict[aioctl])
                    f.write(assign_macros(gdbmi, cmdstypes))
                    f.write('Compl Preprocessed file:%s\n' %
                            processed_filename)
                    f.write('ALL PREPROCESSED FILES:\n')
                    print(txt_filename + ':10')
            item_count += 1

        gdbmi.exit()
        time.sleep(2)

    if len(ioctl_set) == 0:
        print("All ioctl functions are found.")
    else:
        print("%d ioctl functions are not found." % len(ioctl_set))
        print(ioctl_set)
    os.chdir(olddir)
    print('Recovered interfaces are sotred in:\n%s\n%s' % (outdir, outdir2))
    print("Goodbye!")
示例#30
0
class Gdb:
    # Target states
    TARGET_STATE_UNKNOWN = 0
    TARGET_STATE_STOPPED = 1
    TARGET_STATE_RUNNING = 2
    # Target stop reasons
    TARGET_STOP_REASON_UNKNOWN = 0
    TARGET_STOP_REASON_SIGINT = 1
    TARGET_STOP_REASON_SIGTRAP = 2
    TARGET_STOP_REASON_BP = 3
    TARGET_STOP_REASON_WP = 4
    TARGET_STOP_REASON_WP_SCOPE = 5
    TARGET_STOP_REASON_STEPPED = 6
    TARGET_STOP_REASON_FN_FINISHED = 7

    @staticmethod
    def get_logger():
        return logging.getLogger('Gdb')

    def __init__(self, gdb=None):
        # Start gdb process
        self._logger = self.get_logger()
        if os.name == 'nt':
            self._gdbmi = GdbController(gdb_path=gdb)
            # self._gdbmi = GdbControllerWin(gdb_path=gdb)
        else:
            self._gdbmi = GdbController(gdb_path=gdb)
        self._resp_cache = []
        self._target_state = self.TARGET_STATE_UNKNOWN
        self._target_stop_reason = self.TARGET_STOP_REASON_UNKNOWN
        self._curr_frame = None
        self._curr_wp_val = None

    def _on_notify(self, rec):
        if rec['message'] == 'stopped':
            self._target_state = self.TARGET_STATE_STOPPED
            self._curr_frame = rec['payload']['frame']
            if 'reason' in rec['payload']:
                if rec['payload']['reason'] == 'breakpoint-hit':
                    self._target_stop_reason = self.TARGET_STOP_REASON_BP
                elif rec['payload']['reason'] == 'watchpoint-trigger':
                    self._target_stop_reason = self.TARGET_STOP_REASON_WP
                    self._curr_wp_val = rec['payload']['value']
                elif rec['payload']['reason'] == 'watchpoint-scope':
                    self._target_stop_reason = self.TARGET_STOP_REASON_WP_SCOPE
                elif rec['payload']['reason'] == 'end-stepping-range':
                    self._target_stop_reason = self.TARGET_STOP_REASON_STEPPED
                elif rec['payload']['reason'] == 'function-finished':
                    self._target_stop_reason = self.TARGET_STOP_REASON_FN_FINISHED
                elif rec['payload']['reason'] == 'signal-received':
                    if rec['payload']['signal-name'] == 'SIGINT':
                        self._target_stop_reason = self.TARGET_STOP_REASON_SIGINT
                    elif rec['payload']['signal-name'] == 'SIGTRAP':
                        self._target_stop_reason = self.TARGET_STOP_REASON_SIGTRAP
                    else:
                        self._logger.warning('Unknown signal received "%s"!',
                                             rec['payload']['signal-name'])
                        self._target_stop_reason = self.TARGET_STOP_REASON_UNKNOWN
                else:
                    self._logger.warning('Unknown target stop reason "%s"!',
                                         rec['payload']['reason'])
                    self._target_stop_reason = self.TARGET_STOP_REASON_UNKNOWN
            else:
                self._target_stop_reason = self.TARGET_STOP_REASON_UNKNOWN
        elif rec['message'] == 'running':
            self._target_state = self.TARGET_STATE_RUNNING

    def _parse_mi_resp(self, new_resp, new_tgt_state):
        result = None
        result_body = None
        old_state = self._target_state
        # if any cached records go first
        resp = self._resp_cache + new_resp
        processed_recs = 0
        for rec in resp:
            processed_recs += 1
            if rec['type'] == 'log':
                self._logger.debug('LOG: %s', pformat(rec['payload']))
            elif rec['type'] == 'console':
                self._logger.info('CONS: %s', pformat(rec['payload']))
            elif rec['type'] == 'notify':
                self._logger.info('NOTIFY: %s %s', rec['message'],
                                  pformat(rec['payload']))
                self._on_notify(rec)
                # stop upon result receiption if we do not expect target state change
                if self._target_state != old_state and self._target_state == new_tgt_state:
                    self._logger.debug('new target state %d',
                                       self._target_state)
                    break
            elif rec['type'] == 'result':
                self._logger.debug('RESULT: %s %s', rec['message'],
                                   pformat(rec['payload']))
                result = rec['message']
                result_body = rec['payload']
                # stop upon result receiption if we do not expect target state change
                if not new_tgt_state:
                    break
        # cache unprocessed records
        self._resp_cache = resp[processed_recs:]
        # self._logger.debug('cached recs: %s', pformat(self._resp_cache))
        return result, result_body

    def _mi_cmd_run(self, cmd, new_tgt_state=None, tmo=5):
        self._logger.debug('MI->: %s', cmd)
        response = []
        if tmo:
            end = time.time() + tmo
            try:
                response = self._gdbmi.write(cmd, timeout_sec=tmo)
            except:
                self._gdbmi.verify_valid_gdb_subprocess()
        else:
            while len(response) == 0:
                response = self._gdbmi.write(cmd, raise_error_on_timeout=False)
        self._logger.debug('MI<-:\n%s', pformat(response))
        res, res_body = self._parse_mi_resp(response, new_tgt_state)
        while not res:
            # check for result report from GDB
            response = self._gdbmi.get_gdb_response(
                1, raise_error_on_timeout=False)
            if len(response) == 0:
                if tmo and (time.time() >= end):
                    raise DebuggerTargetStateTimeoutError(
                        'Failed to wait for completion of command "%s" / %s!' %
                        (cmd, tmo))
            else:
                self._logger.debug('MI<-:\n%s', pformat(response))
                res, res_body = self._parse_mi_resp(response, new_tgt_state)
        return res, res_body

    def console_cmd_run(self, cmd):
        self._mi_cmd_run('-interpreter-exec console %s' % cmd)

    def target_select(self, tgt_type, tgt_params):
        # -target-select type parameters
        res, _ = self._mi_cmd_run('-target-select %s %s' %
                                  (tgt_type, tgt_params))
        if res != 'connected':
            raise DebuggerError('Failed to connect to "%s %s"!' %
                                (tgt_type, tgt_params))

    def target_disconnect(self):
        # -target-disconnect
        self._mi_cmd_run('-target-disconnect')

    def target_reset(self, action='halt'):
        self.monitor_run('reset %s' % action)
        if action == 'halt':
            self.wait_target_state(self.TARGET_STATE_STOPPED, 5)
            self.console_cmd_run('flushregs')

    def target_download(self):
        raise NotImplementedError('target_download')

    def target_program(self, file_name, off, actions='verify', tmo=30):
        # actions can be any or both of 'verify reset'
        self.monitor_run(
            'program_esp %s %s 0x%x' % (fixup_path(file_name), actions, off),
            tmo)

    def exec_file_set(self, file_path):
        # -file-exec-and-symbols file
        self._logger.debug('exec_file_set %s' % file_path)
        res, _ = self._mi_cmd_run('-file-exec-and-symbols %s' %
                                  fixup_path(file_path))
        if res != 'done':
            raise DebuggerError('Failed to set program file!')

    def exec_interrupt(self):
        global OS_INT_SIG
        # Hack, unfortunately GDB does not react on -exec-interrupt,
        # so send CTRL+C to it
        self._logger.debug('MI->: send SIGINT')
        self._gdbmi.gdb_process.send_signal(OS_INT_SIG)
        # # -exec-interrupt [--all|--thread-group N]
        # res,_ = self._mi_cmd_run('-exec-interrupt --all')
        # if res != 'done':
        #     raise DebuggerError('Failed to stop program!')

    def exec_continue(self):
        # -exec-continue [--reverse] [--all|--thread-group N]
        res, _ = self._mi_cmd_run('-exec-continue --all')
        if res != 'running':
            raise DebuggerError('Failed to continue program!')

    def exec_jump(self, loc):
        # -exec-jump location
        res, _ = self._mi_cmd_run('-exec-jump %s' % loc)
        if res != 'running':
            raise DebuggerError('Failed to make jump in program!')

    def exec_next(self):
        # -exec-next [--reverse]
        res, _ = self._mi_cmd_run('-exec-next')
        if res != 'running':
            raise DebuggerError('Failed to step over!')

    def exec_step(self):
        # -exec-step [--reverse]
        res, _ = self._mi_cmd_run('-exec-step')
        if res != 'running':
            raise DebuggerError('Failed to step in!')

    def exec_finish(self):
        # -exec-finish [--reverse]
        res, _ = self._mi_cmd_run('-exec-finish')
        if res != 'running':
            raise DebuggerError('Failed to step out!')

    def exec_next_insn(self):
        # -exec-next-instruction [--reverse]
        res, _ = self._mi_cmd_run('-exec-next-instruction')
        if res != 'running':
            raise DebuggerError('Failed to step insn!')

    def data_eval_expr(self, expr):
        # -data-evaluate-expression expr
        res, res_body = self._mi_cmd_run('-data-evaluate-expression %s' % expr)
        if res != 'done' or not res_body or 'value' not in res_body:
            raise DebuggerError('Failed to eval expression!')
        return res_body['value']

    def get_reg(self, nm):
        sval = self.data_eval_expr('$%s' % nm)
        # for PC we get something like '0x400e0db8 <gpio_set_direction>'
        # TODO: use regexp to extract value
        fn_start = sval.find(' <')
        if fn_start != -1:
            sval = sval[:fn_start]
        return int(sval, 0)

    def get_variables_at_frame(self, thread_num=None, frame_num=0):
        # -stack-list-variables [ --no-frame-filters ] [ --skip-unavailable ] print-values
        if thread_num:
            cmd = '-stack-list-variables --thread %d --frame %d --all-values' % (
                thread_num, frame_num)
        else:
            cmd = '-stack-list-variables --all-values'
        res, res_body = self._mi_cmd_run(cmd)
        if res != 'done' or not res_body or 'variables' not in res_body:
            raise DebuggerError(
                'Failed to get variables @ frame %d of thread %d!' %
                (frame_num, thread_num))
        return res_body['variables']

    def get_backtrace(self):
        # -stack-list-frames [ --no-frame-filters low-frame high-frame ]
        res, res_body = self._mi_cmd_run('-stack-list-frames')
        if res != 'done' or not res_body or 'stack' not in res_body:
            raise DebuggerError('Failed to get backtrace!')
        return res_body['stack']

    def select_frame(self, frame):
        # -stack-select-frame framenum
        res, _ = self._mi_cmd_run('-stack-select-frame %d' % frame)
        if res != 'done':
            raise DebuggerError('Failed to get backtrace!')

    def add_bp(self, loc, ignore_count=0, cond=''):
        # -break-insert [ -t ] [ -h ] [ -f ] [ -d ] [ -a ] [ -c condition ] [ -i ignore-count ] [ -p thread-id ] [ location ]
        cmd_args = '-i %d %s' % (ignore_count, loc)
        if len(cond):
            cmd_args = '-c "%s" %s' % (cond, cmd_args)
        res, res_body = self._mi_cmd_run('-break-insert %s' % cmd_args)
        if res != 'done' or not res_body or 'bkpt' not in res_body or 'number' not in res_body[
                'bkpt']:
            raise DebuggerError('Failed to insert BP!')
        return res_body['bkpt']['number']

    def add_wp(self, exp, tp='w'):
        # -break-watch [ -a | -r ] expr
        cmd_args = '"%s"' % exp
        if tp == 'r':
            cmd_args = '-r %s' % cmd_args
        elif tp == 'rw':
            cmd_args = '-a %s' % cmd_args
        res, res_body = self._mi_cmd_run('-break-watch %s' % cmd_args)
        if res != 'done' or not res_body:
            raise DebuggerError('Failed to insert WP!')
        if tp == 'w':
            if 'wpt' not in res_body or 'number' not in res_body['wpt']:
                raise DebuggerError('Failed to insert WP!')
            return res_body['wpt']['number']
        elif tp == 'r':
            if 'hw-rwpt' not in res_body or 'number' not in res_body['hw-rwpt']:
                raise DebuggerError('Failed to insert RWP!')
            return res_body['hw-rwpt']['number']
        elif tp == 'rw':
            if 'hw-awpt' not in res_body or 'number' not in res_body['hw-awpt']:
                raise DebuggerError('Failed to insert AWP!')
            return res_body['hw-awpt']['number']
        return None

    def delete_bp(self, bp):
        # -break-delete ( breakpoint )+
        res, _ = self._mi_cmd_run('-break-delete %s' % bp)
        if res != 'done':
            raise DebuggerError('Failed to delete BP!')

    def monitor_run(self, cmd, tmo=None):
        res, resp = self._mi_cmd_run('mon %s' % cmd, tmo=tmo)
        if res != 'done':
            raise DebuggerError('Failed to run monitor cmd "%s"!' % cmd)
        return resp

    def wait_target_state(self, state, tmo=None):
        if tmo:
            end = time.time() + tmo
        while self._target_state != state:
            recs = []
            if len(self._resp_cache):
                recs = self._resp_cache
            else:
                # check for target state change report from GDB
                recs = self._gdbmi.get_gdb_response(
                    1, raise_error_on_timeout=False)
                if tmo and len(recs) == 0 and time.time() >= end:
                    raise DebuggerTargetStateTimeoutError(
                        "Failed to wait for target state %d!" % state)
            self._parse_mi_resp(recs, state)
        return self._target_stop_reason

    def get_target_state(self):
        return self._target_state, self._target_stop_reason

    def get_current_frame(self):
        return self._curr_frame

    def get_current_wp_val(self):
        return self._curr_wp_val

    def connect(self):
        global OOCD_PORT
        self.target_select('remote', ':%d' % OOCD_PORT)

    def disconnect(self):
        self.target_disconnect()

    def get_thread_info(self, thread_id=None):
        # -thread-info [ thread-id ]
        if thread_id:
            cmd = '-thread-info %d' % thread_id
        else:
            cmd = '-thread-info'
        res, res_body = self._mi_cmd_run(cmd)
        if res != 'done' or not res_body or 'threads' not in res_body or 'current-thread-id' not in res_body:
            raise DebuggerError('Failed to get thread info!')
        return (res_body['current-thread-id'], res_body['threads'])

    def set_thread(self, num):
        res, _ = self._mi_cmd_run('-thread-select %d' % num)
        if res != 'done':
            raise DebuggerError('Failed to set thread!')
        return res

    def get_thread_ids(self):
        # -thread-list-ids expr
        res, thread_ids = self._mi_cmd_run('-thread-list-ids')
        if res != 'done':
            raise DebuggerError('Failed to eval expression!')
        return thread_ids

    def gcov_dump(self, on_the_fly=True):
        if on_the_fly:
            cmd = '%s gcov' % Oocd.current_target_name_get()
        else:
            cmd = '%s gcov dump' % Oocd.current_target_name_get()
        self.monitor_run(cmd, tmo=20)

    def sysview_start(self, file1, file2=''):
        self.monitor_run('%s sysview start %s %s' %
                         (Oocd.current_target_name_get(), file1, file2))

    def sysview_stop(self):
        self.monitor_run('%s sysview stop' % Oocd.current_target_name_get())