fix errno command (#1112)

* fix errno command

* fix isort

* try to fix CI

* Update test_command_errno.py
This commit is contained in:
Disconnect3d 2022-09-05 02:46:51 +02:00 committed by GitHub
parent 9755a40d7b
commit 42f32d7cc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 29 deletions

View File

@ -339,7 +339,7 @@ class _ArgparsedCommand(Command):
class ArgparsedCommand:
"""Adds documentation and offloads parsing for a Command via argparse"""
def __init__(self, parser_or_desc, aliases=[]):
def __init__(self, parser_or_desc, aliases=[], command_name=None):
"""
:param parser_or_desc: `argparse.ArgumentParser` instance or `str`
"""
@ -348,6 +348,8 @@ class ArgparsedCommand:
else:
self.parser = parser_or_desc
self.aliases = aliases
self._command_name = command_name
# We want to run all integer and otherwise-unspecified arguments
# through fix() so that GDB parses it.
for action in self.parser._actions:
@ -360,8 +362,8 @@ class ArgparsedCommand:
def __call__(self, function):
for alias in self.aliases:
_ArgparsedCommand(self.parser, function, alias)
return _ArgparsedCommand(self.parser, function)
_ArgparsedCommand(self.parser, function, command_name=alias)
return _ArgparsedCommand(self.parser, function, command_name=self._command_name)
# We use a 64-bit max value literal here instead of pwndbg.arch.current

View File

@ -1,14 +1,14 @@
import argparse
import errno as _errno
import errno
import gdb
import pwndbg as _pwndbg
import pwndbg.arch as _arch
import pwndbg.auxv
import pwndbg.commands
import pwndbg.regs
import pwndbg.symbol
_errno.errorcode[0] = "OK"
errno.errorcode[0] = "OK"
parser = argparse.ArgumentParser(
description="""
@ -24,24 +24,25 @@ parser.add_argument(
)
@_pwndbg.commands.ArgparsedCommand(parser)
@pwndbg.commands.ArgparsedCommand(parser, command_name="errno")
@pwndbg.commands.OnlyWhenRunning
def errno(err):
def errno_(err):
if err is None:
# Dont ask.
errno_location = pwndbg.symbol.get("__errno_location")
err = pwndbg.memory.int(errno_location)
# err = int(gdb.parse_and_eval('*((int *(*) (void)) __errno_location) ()'))
# Try to get the `errno` variable value
# if it does not exist, get the errno variable from its location
try:
err = int(gdb.parse_and_eval("errno"))
except gdb.error:
try:
err = int(gdb.parse_and_eval("*((int *(*) (void)) __errno_location) ()"))
except gdb.error:
print(
"Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (was libc.so loaded already?)"
)
return
err = abs(int(err))
if err >> 63:
err -= 1 << 64
elif err >> 31:
err -= 1 << 32
msg = _errno.errorcode.get(int(err), "Unknown error code")
print("Errno %i: %s" % (err, msg))
msg = errno.errorcode.get(int(err), "Unknown error code")
print("Errno %s: %s" % (err, msg))
parser = argparse.ArgumentParser(
@ -58,8 +59,8 @@ parser.add_argument(
)
@_pwndbg.commands.ArgparsedCommand(parser)
def pwndbg(filter_pattern):
@pwndbg.commands.ArgparsedCommand(parser, command_name="pwndbg")
def pwndbg_(filter_pattern):
for name, docs in list_and_filter_commands(filter_pattern):
print("%-20s %s" % (name, docs))
@ -69,19 +70,19 @@ parser.add_argument("a", type=int, help="The first address.")
parser.add_argument("b", type=int, help="The second address.")
@_pwndbg.commands.ArgparsedCommand(parser)
@pwndbg.commands.ArgparsedCommand(parser)
def distance(a, b):
"""Print the distance between the two arguments"""
a = int(a) & _arch.ptrmask
b = int(b) & _arch.ptrmask
a = int(a) & pwndbg.arch.ptrmask
b = int(b) & pwndbg.arch.ptrmask
distance = b - a
print("%#x->%#x is %#x bytes (%#x words)" % (a, b, distance, distance // _arch.ptrsize))
print("%#x->%#x is %#x bytes (%#x words)" % (a, b, distance, distance // pwndbg.arch.ptrsize))
def list_and_filter_commands(filter_str):
sorted_commands = list(_pwndbg.commands.commands)
sorted_commands = list(pwndbg.commands.commands)
sorted_commands.sort(key=lambda x: x.__name__)
if filter_str:

View File

@ -0,0 +1,48 @@
import gdb
import pwndbg
import pwndbg.memory
import pwndbg.regs
import tests
# We use the heap_vis binary as it enforces pthreads and so will have TLS on all distros
REFERENCE_BINARY = tests.binaries.get("heap_vis.out")
def test_command_errno(start_binary):
"""
Tests the errno command display
"""
start_binary(REFERENCE_BINARY)
# Since start_binary does 'starti' which stops on the very first instruction
# the errno is not yet an available symbol, because the libc library it is
# defined in is not yet loaded
result = "".join(gdb.execute("errno", to_string=True).splitlines())
assert (
result
== "Could not determine error code automatically: neither `errno` nor `__errno_location` symbols were provided (was libc.so loaded already?)"
)
gdb.execute("break main")
gdb.execute("continue")
result = gdb.execute("errno", to_string=True)
assert result == "Errno 0: OK\n"
gdb.execute("set *(int*)&errno=11")
result = gdb.execute("errno", to_string=True)
assert result == "Errno 11: EAGAIN\n"
gdb.execute("set *(int*)&errno=111")
result = gdb.execute("errno", to_string=True)
assert result == "Errno 111: ECONNREFUSED\n"
result = gdb.execute("errno 8", to_string=True)
assert result == "Errno 8: ENOEXEC\n"
result = gdb.execute("errno 123", to_string=True)
assert result == "Errno 123: ENOMEDIUM\n"
result = gdb.execute("errno 250", to_string=True)
assert result == "Errno 250: Unknown error code\n"