mirror of https://github.com/pwndbg/pwndbg.git
Go runtime value dumping (#2329)
* basic go value dumping * better error handling and misc improvements * minor documentation changes * satisfy mypy * struct parsing and bug fix * satisfy mypy * deal with evacuated buckets * better error message for invalid expressions * convert bytearray to bytes before repr * support for recursive types and better type dumping * better QOL for go-dump command * formatting options and debug/pretty printing * add go dumping unit tests * deal with differences in old go version * lint * old go versions missing any alias * proper name dumping for go versions prior to 1.17 * lint * go is being weird on CI * warn instead of erroring * function and interface dumpingpull/2366/head
parent
b188baa2c7
commit
94ee021f42
@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
import pwndbg.commands
|
||||
import pwndbg.gdblib.arch
|
||||
import pwndbg.gdblib.config
|
||||
import pwndbg.gdblib.godbg
|
||||
import pwndbg.gdblib.memory
|
||||
import pwndbg.gdblib.regs
|
||||
from pwndbg.commands import CommandCategory
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Dumps a Go value of a given type at a specified address."
|
||||
)
|
||||
parser.add_argument(
|
||||
"ty",
|
||||
type=str,
|
||||
help="Go type of value to dump, e.g. map[int]string, or the address of a type to resolve at runtime, e.g. 0x408860",
|
||||
)
|
||||
parser.add_argument(
|
||||
"address",
|
||||
type=pwndbg.commands.AddressExpr,
|
||||
help="Address to dump",
|
||||
)
|
||||
parser.add_argument("-x", "--hex", action="store_true", help="Display non-pointer integers as hex")
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--decimals",
|
||||
nargs="?",
|
||||
type=int,
|
||||
help="Configures the number of decimal places to display for floating points",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--debug",
|
||||
action="store_true",
|
||||
help="Shows debug info, like addresses for slice/map elements, slice capacity, etc.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--pretty",
|
||||
action="store_true",
|
||||
help="Enables pretty printing",
|
||||
)
|
||||
|
||||
|
||||
@pwndbg.commands.ArgparsedCommand(
|
||||
parser, category=CommandCategory.MEMORY, command_name="go-dump", aliases=["god"]
|
||||
)
|
||||
@pwndbg.commands.OnlyWhenRunning
|
||||
def go_dump(
|
||||
ty: str, address: int, hex: bool, decimals: int | None, debug: bool, pretty: bool
|
||||
) -> None:
|
||||
try:
|
||||
ty_addr = int(ty, 0)
|
||||
(_, parsed_ty) = pwndbg.gdblib.godbg.decode_runtime_type(ty_addr)
|
||||
if parsed_ty is None:
|
||||
print("Failed to decode runtime type.")
|
||||
return
|
||||
except ValueError:
|
||||
parsed_ty = pwndbg.gdblib.godbg.parse_type(ty)
|
||||
fmt = pwndbg.gdblib.godbg.FormatOpts(
|
||||
int_hex=hex, float_decimals=decimals, debug=debug, pretty=pretty
|
||||
)
|
||||
print(parsed_ty.dump(address, fmt))
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Dumps a Go runtime reflection type at a specified address."
|
||||
)
|
||||
parser.add_argument(
|
||||
"address",
|
||||
type=pwndbg.commands.AddressExpr,
|
||||
help="Address to dump",
|
||||
)
|
||||
|
||||
|
||||
@pwndbg.commands.ArgparsedCommand(
|
||||
parser, category=CommandCategory.MEMORY, command_name="go-type", aliases=["goty"]
|
||||
)
|
||||
@pwndbg.commands.OnlyWhenRunning
|
||||
def go_type(address: int) -> None:
|
||||
meta, ty = pwndbg.gdblib.godbg.decode_runtime_type(address, True)
|
||||
print(f" Name: {meta.name}")
|
||||
print(f" Kind: {meta.kind.name}")
|
||||
print(f" Size: {meta.size} ({meta.size:#x})")
|
||||
print(f"Align: {meta.align}")
|
||||
print(f"Parse: {ty}")
|
||||
if ty:
|
||||
data = ty.additional_metadata()
|
||||
if data:
|
||||
print("\n".join(data))
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func testFunc(x interface{}) *interface{} {
|
||||
fmt.Println(x)
|
||||
return &x // leak x to force it to be allocated somewhere
|
||||
}
|
||||
|
||||
func main() {
|
||||
testFunc(map[string]int{"a": 1, "b": 2, "c": 3})
|
||||
testFunc([]struct {
|
||||
a int
|
||||
b string
|
||||
}{{a: 1, b: "first"}, {a: 2, b: "second"}})
|
||||
testFunc([3]complex64{1.1 + 2.2i, -2.5 - 5i, 4.2 - 2.1i})
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
@ -1,3 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
Loading…
Reference in new issue