mirror of https://github.com/pwndbg/pwndbg.git
Improve convenience function helps and autogenerate documentation (#2900)
* expand and add examples to pwndbg convenience functions * update usage descriptions in _gen_* * refactor out some common logic * implement function doc generation * change some mkdocs defaults around to be better for the general case * generate function docs * cleanup some examples, help, and quote escaping explanation * move fsbase and gsbase definitions (and use decorator) * cleanup signature for fsbase and gsbase * autogen functions * type annotation * fix ida and binja descriptions * rename arguments, reorder docs for `help function` and assert convention * add missing imports * use inspect.getdoc instead of directly accessing __doc__ for more consistency across python versions * regen docs with getdoc() * rewire exit and lint * let users know about convenience functions through the `pwndbg` command * sys.exit instead of exitpull/2923/head
parent
d7664e2501
commit
52a4be5e50
@ -0,0 +1,441 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
---
|
||||
<!-- THIS WHOLE FILE IS AUTOGENERATED. DO NOT MODIFY IT. See scripts/generate_docs.sh -->
|
||||
|
||||
|
||||
|
||||
|
||||
# Functions
|
||||
|
||||
|
||||
pwndbg provides a set of functions which can be used during expression evaluation to
|
||||
quickly perform common calculations. These can even be passed to other commands as arguments.
|
||||
Currently, they only work in gdb.
|
||||
|
||||
To see a list of all functions, including those built into gdb, use `help function`. To see
|
||||
the help of any given function use `help function function_name`. Function invokation must
|
||||
include a preceding $ sign and must include brackets. For instance, invoke the `environ`
|
||||
function like so:
|
||||
```
|
||||
pwndbg> p $environ("LANG")
|
||||
$2 = (signed char *) 0x7fffffffe6da "LANG=en_US.UTF-8"
|
||||
```
|
||||
If the result of the function is being passed to a pwndbg command, make sure to either escape
|
||||
the function argument's quotes, or put the whole function call in quotes.
|
||||
```
|
||||
pwndbg> tele $environ("LANG")
|
||||
usage: telescope [-h] [-r] [-f] [-i] [address] [count]
|
||||
telescope: error: argument address: debugger couldn't resolve argument '$environ(LANG)':
|
||||
No symbol "LANG" in current context.
|
||||
pwndbg> tele $environ(\"LANG\")
|
||||
00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8'
|
||||
01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8'
|
||||
02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400
|
||||
[...]
|
||||
pwndbg> tele '$environ("LANG")'
|
||||
00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8'
|
||||
01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8'
|
||||
02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400
|
||||
[...]
|
||||
```
|
||||
## pwndbg functions
|
||||
|
||||
### **rebase**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
rebase(addr: gdb.Value | int) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Return address rebased onto the executable's mappings.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p/x $rebase(0xd9020)
|
||||
$1 = 0x55555562d020
|
||||
pwndbg> vmmap
|
||||
0x555555554000 0x55555556f000 r--p 1b000 0 /usr/bin/bash
|
||||
0x55555556f000 0x55555562d000 r-xp be000 1b000 /usr/bin/bash
|
||||
0x55555562d000 0x55555565e000 r--p 31000 d9000 /usr/bin/bash
|
||||
[...]
|
||||
pwndbg> p $rebase(0xd9020) == 0x555555554000 + 0xd9020
|
||||
$2 = 1
|
||||
pwndbg> tele $rebase(0xd9020)
|
||||
00:0000│ 0x55555562d020 ◂— 0x204900636f6c6c61 /* 'alloc' */
|
||||
01:0008│ 0x55555562d028 ◂— 'have no name!'
|
||||
02:0010│ 0x55555562d030 ◂— 0x65720021656d616e /* 'name!' */
|
||||
03:0018│ 0x55555562d038 ◂— 'adline stdin'
|
||||
[...]
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **base**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
base(name_pattern: gdb.Value | str) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Return the base address of the first memory mapping containing the given name.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p/x $base("libc")
|
||||
$4 = 0x7ffff7d4b000
|
||||
pwndbg> vmmap libc
|
||||
0x7ffff7d4a000 0x7ffff7d4b000 rw-p 1000 6e000 /usr/lib/libncursesw.so.6.5
|
||||
► 0x7ffff7d4b000 0x7ffff7d6f000 r--p 24000 0 /usr/lib/libc.so.6
|
||||
► 0x7ffff7d6f000 0x7ffff7ed6000 r-xp 167000 24000 /usr/lib/libc.so.6
|
||||
► 0x7ffff7ed6000 0x7ffff7f2b000 r--p 55000 18b000 /usr/lib/libc.so.6
|
||||
► 0x7ffff7f2b000 0x7ffff7f2f000 r--p 4000 1e0000 /usr/lib/libc.so.6
|
||||
► 0x7ffff7f2f000 0x7ffff7f31000 rw-p 2000 1e4000 /usr/lib/libc.so.6
|
||||
0x7ffff7f31000 0x7ffff7f39000 rw-p 8000 0 [anon_7ffff7f31]
|
||||
pwndbg> tele $base(\"libc\")+0x1337
|
||||
00:0000│ 0x7ffff7d4c337 ◂— 0x80480a04214000f0
|
||||
01:0008│ 0x7ffff7d4c33f ◂— 0x8040c02204452040
|
||||
02:0010│ 0x7ffff7d4c347 ◂— 0x20042400000200
|
||||
03:0018│ 0x7ffff7d4c34f ◂— 0x20 /* ' ' */
|
||||
[...]
|
||||
```
|
||||
|
||||
Beware of accidentally matching the wrong mapping. For instance, if the loaded
|
||||
executable contained the string "libc" anywhere in it's path, it would've been
|
||||
returned.
|
||||
|
||||
----------
|
||||
|
||||
### **hex2ptr**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
hex2ptr(hex_string: gdb.Value | str) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Converts a hex string to a little-endian address and returns the address.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p/x $hex2ptr("20 74 ed f7 ff 7f")
|
||||
$1 = 0x7ffff7ed7420
|
||||
pwndbg> p/x $hex2ptr("2074edf7ff7f")
|
||||
$2 = 0x7ffff7ed7420
|
||||
pwndbg> distance '$base("libc")' '$hex2ptr("20 74 ed f7 ff 7f")'
|
||||
0x7ffff7d4b000->0x7ffff7ed7420 is 0x18c420 bytes (0x31884 words)
|
||||
```
|
||||
|
||||
Especially useful for quickly converting pwntools output.
|
||||
|
||||
----------
|
||||
|
||||
### **argc**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
argc() -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get the number of program arguments.
|
||||
Evaluates to argc.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p $argc()
|
||||
$1 = 2
|
||||
pwndbg> argv
|
||||
00:0000│ 0x7fffffffe288 —▸ 0x7fffffffe659 ◂— '/usr/bin/cat'
|
||||
01:0008│ 0x7fffffffe290 —▸ 0x7fffffffe666 ◂— 'gdbinit.py'
|
||||
02:0010│ 0x7fffffffe298 ◂— 0
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **argv**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
argv(index: gdb.Value) -> gdb.Value
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get the n-th program argument.
|
||||
Evaluate argv on the supplied value.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p $argv(0)
|
||||
$11 = (signed char *) 0x7fffffffe666 "/usr/bin/sh"
|
||||
pwndbg> argv
|
||||
00:0000│ 0x7fffffffe2a8 —▸ 0x7fffffffe666 ◂— '/usr/bin/sh'
|
||||
01:0008│ 0x7fffffffe2b0 ◂— 0
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **environ**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
environ(env_name: gdb.Value) -> gdb.Value
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get an environment variable by name.
|
||||
Evaluate getenv() on the supplied value.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p $environ("LANG")
|
||||
$2 = (signed char *) 0x7fffffffebfb "LANG=en_US.UTF-8"
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **envp**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
envp(index: gdb.Value) -> gdb.Value
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get the n-th environment variable.
|
||||
Evaluate envp on the supplied value.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p $envp(0x3F)
|
||||
$13 = (signed char *) 0x7fffffffef7d "LANG=en_US.UTF-8"
|
||||
pwndbg> p $envp(0x3F) == $environ("LANG")
|
||||
$14 = 1
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **fsbase**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
fsbase(offset: gdb.Value = gdb.Value(0)) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get the value of the FS segment register.
|
||||
Only valid on x86(-64).
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p/x $fsbase()
|
||||
$3 = 0x7ffff7cdab80
|
||||
pwndbg> p $fs_base == $fsbase()
|
||||
$4 = 1
|
||||
pwndbg> x/gx $fsbase(0x28)
|
||||
0x7ffff7cdaba8: 0x4da926e1668e5a00
|
||||
pwndbg> x/gx $fsbase(0x30)
|
||||
0x7ffff7cdabb0: 0x190a86d93bccf0ad
|
||||
pwndbg> tls
|
||||
Thread Local Storage (TLS) base: 0x7ffff7cdab80
|
||||
TLS is located at:
|
||||
0x7ffff7cda000 0x7ffff7cdc000 rw-p 2000 0 [anon_7ffff7cda]
|
||||
Dumping the address:
|
||||
tcbhead_t @ 0x7ffff7cdab80
|
||||
0x00007ffff7cdab80 +0x0000 tcb : 0x7ffff7cdab80
|
||||
0x00007ffff7cdab88 +0x0008 dtv : 0x7ffff7cdb4f0
|
||||
0x00007ffff7cdab90 +0x0010 self : 0x7ffff7cdab80
|
||||
0x00007ffff7cdab98 +0x0018 multiple_threads : 0x0
|
||||
0x00007ffff7cdab9c +0x001c gscope_flag : 0x0
|
||||
0x00007ffff7cdaba0 +0x0020 sysinfo : 0x0
|
||||
0x00007ffff7cdaba8 +0x0028 stack_guard : 0x4da926e1668e5a00
|
||||
0x00007ffff7cdabb0 +0x0030 pointer_guard : 0x190a86d93bccf0ad
|
||||
[...]
|
||||
pwndbg> canary
|
||||
[...]
|
||||
Canary = 0x4da926e1668e5a00 (may be incorrect on != glibc)
|
||||
[...]
|
||||
```
|
||||
FS will usually point to the start of the TLS. If you're not providing an
|
||||
offset, it is usually easier to use gdb's builtin $fs_base variable.
|
||||
|
||||
----------
|
||||
|
||||
### **gsbase**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
gsbase(offset: gdb.Value = gdb.Value(0)) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Get the value of the GS segment register.
|
||||
Only valid on x86(-64).
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> p/x $gsbase()
|
||||
$1 = 0x0
|
||||
```
|
||||
The value of the GS register is more interesting when doing kernel debugging:
|
||||
```
|
||||
pwndbg> p/x $gsbase()
|
||||
$1 = 0xffff999287a00000
|
||||
pwndbg> tele $gsbase()
|
||||
00:0000│ 0xffff999287a00000 ◂— 0
|
||||
... ↓ 4 skipped
|
||||
05:0028│ 0xffff999287a00028 ◂— 0xd6aa9b336d52a400
|
||||
06:0030│ 0xffff999287a00030 ◂— 0
|
||||
07:0038│ 0xffff999287a00038 ◂— 0
|
||||
pwndbg> p $gsbase() == $gs_base
|
||||
$2 = 1
|
||||
```
|
||||
If you're not providing an offset, it is usually easier to use gdb's
|
||||
builtin $gs_base variable.
|
||||
|
||||
----------
|
||||
|
||||
### **bn_sym**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
bn_sym(name_val: gdb.Value) -> int | None
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Lookup a symbol's address by name from Binary Ninja.
|
||||
|
||||
This function sees symbols like functions and global variables,
|
||||
but not stack local variables, use `bn_var` for that.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> set integration-provider binja
|
||||
Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337
|
||||
Set which provider to use for integration features to 'binja'.
|
||||
pwndbg> p main
|
||||
No symbol "main" in current context.
|
||||
pwndbg> p/x $bn_sym("main")
|
||||
$2 = 0x555555555645
|
||||
pwndbg> b *($bn_sym("main"))
|
||||
Breakpoint 1 at 0x555555555645
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **bn_var**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
bn_var(name_val: gdb.Value) -> int | None
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Lookup a stack variable's address by name from Binary Ninja.
|
||||
|
||||
This function doesn't see functions or global variables,
|
||||
use `bn_sym` for that.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> set integration-provider binja
|
||||
Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337
|
||||
Set which provider to use for integration features to 'binja'.
|
||||
pwndbg> p user_choice
|
||||
No symbol "user_choice" in current context.
|
||||
pwndbg> p/x $bn_var("user_choice")
|
||||
$4 = 0x7fffffffe118
|
||||
pwndbg> vmmap $4
|
||||
0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0 [anon_7ffff7ffe]
|
||||
► 0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack] +0x20118
|
||||
pwndbg> p/x $bn_var("main")
|
||||
TypeError: Could not convert Python object: None.
|
||||
Error while executing Python code.
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **bn_eval**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
bn_eval(expr: gdb.Value) -> int | None
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Parse and evaluate a Binary Ninja expression.
|
||||
|
||||
Read more about binary ninja expressions here:
|
||||
https://api.binary.ninja/binaryninja.binaryview-module.html#binaryninja.binaryview.BinaryView.parse_expression
|
||||
|
||||
All registers in the current register set are available as magic variables (e.g. $rip).
|
||||
The $piebase magic variable is also included, with the computed executable base.
|
||||
|
||||
This function cannot see stack local variables.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> set integration-provider binja
|
||||
Pwndbg successfully connected to Binary Ninja (4.2.6455 Personal) xmlrpc: http://127.0.0.1:31337
|
||||
Set which provider to use for integration features to 'binja'.
|
||||
pwndbg> p/x $bn_eval("10+20")
|
||||
$6 = 0x30
|
||||
pwndbg> p/x $bn_eval("main")
|
||||
$7 = 0x1645
|
||||
pwndbg> p/x $rebase($bn_eval("main"))
|
||||
$8 = 0x555555555645
|
||||
pwndbg> p some_global_var
|
||||
No symbol "some_global_var" in current context.
|
||||
pwndbg> p/x $rebase($bn_eval("some_global_var+$rax"))
|
||||
$9 = 0x5555555586b8
|
||||
pwndbg> p $rebase($bn_eval("some_global_var+$rax")) == $bn_sym("some_global_var") + $rax
|
||||
$10 = 1
|
||||
pwndbg> p $bn_eval("$piebase+some_global_var+$rax") == $bn_sym("some_global_var") + $rax
|
||||
$11 = 1
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **ida**
|
||||
|
||||
|
||||
``` {.python .no-copy}
|
||||
ida(name: gdb.Value) -> int
|
||||
```
|
||||
|
||||
|
||||
#### Description
|
||||
Lookup a symbol's address by name from IDA.
|
||||
Evaluate ida.LocByName() on the supplied value.
|
||||
|
||||
This functions doesn't see stack local variables.
|
||||
|
||||
#### Example
|
||||
```
|
||||
pwndbg> set integration-provider ida
|
||||
Pwndbg successfully connected to Ida Pro xmlrpc: http://127.0.0.1:31337
|
||||
Set which provider to use for integration features to 'ida'.
|
||||
pwndbg> p main
|
||||
No symbol "main" in current context.
|
||||
pwndbg> p/x $ida("main")
|
||||
$1 = 0x555555555645
|
||||
pwndbg> b *$ida("main")
|
||||
Breakpoint 2 at 0x555555555645
|
||||
```
|
||||
|
||||
----------
|
||||
@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
You should use scripts/generate_docs.sh and scripts/verify_docs.sh instead
|
||||
of using this.
|
||||
|
||||
If the PWNDBG_GEN_DOC_JUST_VERIFY environment variable
|
||||
is set, then : Exit with non-zero exit status if the docs/functions/ files
|
||||
aren't up to date with the sources. Don't modify anything.
|
||||
|
||||
If it isn't, this fixes up the docs/functions/ files to be up
|
||||
to date with the information from the sources.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from inspect import getdoc
|
||||
from inspect import signature
|
||||
from typing import Dict
|
||||
|
||||
from mdutils.mdutils import MdUtils
|
||||
|
||||
import pwndbg
|
||||
from pwndbg.gdblib.functions import _GdbFunction
|
||||
from scripts._gen_docs_generic import update_files_simple
|
||||
from scripts._gen_docs_generic import verify_existence
|
||||
from scripts._gen_docs_generic import verify_files_simple
|
||||
|
||||
|
||||
def extract_functions() -> Dict[str, _GdbFunction]:
|
||||
"""
|
||||
Returns a dictionary that mapes function names to
|
||||
the corresponding _GdbFunction objects.
|
||||
"""
|
||||
functions = pwndbg.gdblib.functions.functions
|
||||
result = {}
|
||||
|
||||
for f in functions:
|
||||
result[f.name] = f
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def sanitize_signature(func_name: str, sig: str) -> str:
|
||||
"""
|
||||
We need to strip ' from type annotations, and cleanup
|
||||
some functions that don't display properly.
|
||||
"""
|
||||
sig = sig.replace("'", "")
|
||||
match func_name:
|
||||
case "fsbase":
|
||||
sig = re.sub(r"<gdb\.Value object at 0x[0-9a-fA-F]+>", "gdb.Value(0)", sig)
|
||||
case "gsbase":
|
||||
sig = re.sub(r"<gdb\.Value object at 0x[0-9a-fA-F]+>", "gdb.Value(0)", sig)
|
||||
return sig
|
||||
|
||||
|
||||
def convert_to_markdown(named_funcs: Dict[str, _GdbFunction]) -> Dict[str, str]:
|
||||
"""
|
||||
Returns a dict which maps filenames to their markdown contents.
|
||||
It will have only one item (the index.md).
|
||||
"""
|
||||
markdowned = {}
|
||||
|
||||
mdFile = MdUtils(index_path)
|
||||
mdFile.new_header(level=1, title="Functions")
|
||||
intro_text = """
|
||||
pwndbg provides a set of functions which can be used during expression evaluation to
|
||||
quickly perform common calculations. These can even be passed to other commands as arguments.
|
||||
Currently, they only work in gdb.
|
||||
|
||||
To see a list of all functions, including those built into gdb, use `help function`. To see
|
||||
the help of any given function use `help function function_name`. Function invokation must
|
||||
include a preceding $ sign and must include brackets. For instance, invoke the `environ`
|
||||
function like so:
|
||||
```
|
||||
pwndbg> p $environ("LANG")
|
||||
$2 = (signed char *) 0x7fffffffe6da "LANG=en_US.UTF-8"
|
||||
```
|
||||
If the result of the function is being passed to a pwndbg command, make sure to either escape
|
||||
the function argument's quotes, or put the whole function call in quotes.
|
||||
```
|
||||
pwndbg> tele $environ("LANG")
|
||||
usage: telescope [-h] [-r] [-f] [-i] [address] [count]
|
||||
telescope: error: argument address: debugger couldn't resolve argument '$environ(LANG)':
|
||||
No symbol "LANG" in current context.
|
||||
pwndbg> tele $environ(\\"LANG\\")
|
||||
00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8'
|
||||
01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8'
|
||||
02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400
|
||||
[...]
|
||||
pwndbg> tele '$environ("LANG")'
|
||||
00:0000│ 0x7fffffffe6cf ◂— 'LANG=en_US.UTF-8'
|
||||
01:0008│ 0x7fffffffe6d7 ◂— 'US.UTF-8'
|
||||
02:0010│ 0x7fffffffe6df ◂— 0x4e49475542454400
|
||||
[...]
|
||||
```
|
||||
## pwndbg functions
|
||||
"""
|
||||
mdFile.new_paragraph(intro_text.strip())
|
||||
|
||||
for func_name, func in named_funcs.items():
|
||||
mdFile.new_paragraph(f"### **{func_name}**")
|
||||
func_sig = sanitize_signature(func_name, str(signature(func.func)))
|
||||
func_signature_code = f"""
|
||||
``` {{.python .no-copy}}
|
||||
{func_name}{func_sig}
|
||||
```
|
||||
"""
|
||||
if " object at " in func_sig or "<" in func_sig: # '>' is valid in type annotation (->)
|
||||
print(f'Signature of {func_name} is rendered as "{func_sig}", please edit')
|
||||
print("the sanitize_signature() function to display the signature better in the docs.")
|
||||
sys.exit(5)
|
||||
|
||||
mdFile.new_paragraph(func_signature_code)
|
||||
mdFile.new_paragraph(
|
||||
"#### Description\n" + getdoc(func).replace("Example:", "#### Example")
|
||||
)
|
||||
mdFile.new_paragraph("-" * 10)
|
||||
|
||||
hide_nav = "---\nhide:\n - navigation\n---\n"
|
||||
autogen_warning = (
|
||||
"<!-- THIS WHOLE FILE IS AUTOGENERATED. DO NOT MODIFY IT. See scripts/generate_docs.sh -->"
|
||||
)
|
||||
markdowned[index_path] = hide_nav + autogen_warning + "\n" + mdFile.get_md_text()
|
||||
return markdowned
|
||||
|
||||
|
||||
def check_index(scoped_params: Dict[str, list[Parameter]]):
|
||||
assert (
|
||||
len(scoped_params.keys()) == 3
|
||||
and "It seems a new scope has been added, "
|
||||
f"please update the index file ({index_path}) and bump this number accordingly."
|
||||
)
|
||||
|
||||
|
||||
base_path = "docs/functions/" # Must have trailing slash.
|
||||
index_path = base_path + "index.md"
|
||||
|
||||
# ==== Start ====
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
print("This script doesn't accept any arguments.")
|
||||
print("See top of the file for usage.")
|
||||
sys.exit(1)
|
||||
|
||||
just_verify = False
|
||||
if os.getenv("PWNDBG_GEN_DOC_JUST_VERIFY"):
|
||||
just_verify = True
|
||||
|
||||
print("\n==== Function Documentation ====")
|
||||
|
||||
named_functions = extract_functions()
|
||||
markdowned = convert_to_markdown(named_functions)
|
||||
assert len(markdowned) == 1 # Only index.md
|
||||
|
||||
if just_verify:
|
||||
print("Checking if all files are in place..")
|
||||
missing, extra = verify_existence(list(markdowned.keys()), base_path)
|
||||
if missing or extra:
|
||||
print("To add mising files please run ./scripts/generate_docs.sh.")
|
||||
print("To remove extra files please remove them manually.")
|
||||
sys.exit(2)
|
||||
print("Every file is where it should be!")
|
||||
|
||||
print("Verifying contents...")
|
||||
err = verify_files_simple(markdowned)
|
||||
if err:
|
||||
print("VERIFICATION FAILED. The files differ from what would be auto-generated.")
|
||||
print("Error:", err)
|
||||
print("Please run ./scripts/generate_docs.sh from project root and commit the changes.")
|
||||
sys.exit(3)
|
||||
|
||||
print("Verification successful!")
|
||||
else:
|
||||
print("Updating files...")
|
||||
update_files_simple(markdowned)
|
||||
print("Update successful.")
|
||||
|
||||
missing, extra = verify_existence(list(markdowned.keys()), base_path)
|
||||
assert not missing and "Some files (and not the index) are missing, which should be impossible."
|
||||
|
||||
if extra:
|
||||
print("Please delete the extra files by hand.")
|
||||
sys.exit(4)
|
||||
@ -1,4 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Run the generator inside gdb so everything resolves correctly.
|
||||
uv run --group docs gdb --batch -nx --ex "source ./gdbinit.py" --ex "set exception-verbose on" --ex "source ./scripts/_gen_command_docs.py" --ex "source ./scripts/_gen_configuration_docs.py" --quiet
|
||||
uv run --group docs gdb --batch -nx --ex "source ./gdbinit.py" \
|
||||
--ex "set exception-verbose on" \
|
||||
--ex "source ./scripts/_gen_command_docs.py" \
|
||||
--ex "source ./scripts/_gen_configuration_docs.py" \
|
||||
--ex "source ./scripts/_gen_function_docs.py" \
|
||||
--quiet
|
||||
|
||||
Loading…
Reference in new issue