Commit graph

973 commits

Author SHA1 Message Date
SSharshunov
eda5e12b56
librz/arch/c166: Coverity fixes
* CID: 909863
* CID: 909871
* CID: 909855
* CID: 909865
* CID: 909864
* CID: 909872
* CID: 909867
* CID: 909843
* CID: 909847
* CID: 909873
* CID 909856
2026-07-09 00:20:49 +08:00
Khairul Azhar Kasmiran
4897885c5c
Uniquify function flag realnames (#6601) 2026-07-05 22:33:25 +08:00
NOT XVilka
6f630b785e
Fix memory leaks in bin, type parser, core meta and debug (#6594)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-07-05 02:56:19 +08:00
Naren Sirigere
3c02fa5618
Fix x64 and x86 SEH analysis (#6558) 2026-07-04 15:46:13 +08:00
NOT XVilka
84b2f31035
Fix memory leaks in arch and core (#6590)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-07-04 13:36:06 +08:00
NOT XVilka
851ab98455
Fix memory leaks across core, bin, and PDB parsing (#6579)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-30 19:04:28 +08:00
NOT XVilka
402e0fc1b6
librz/bin: fix MTK image parsing on BE host (#6580)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-30 14:52:32 +08:00
Naren Sirigere
478117db3b
Bump rz-libdemangle to get the dlang demangler (#6566)
Fix check_dlang() to check if the string starts with "_D" followed by any digit
2026-06-28 12:50:08 +08:00
Rot127
2478a95874
Fix performance for GOT offset lookup via a lookup table. (#6555) 2026-06-24 11:30:00 +08:00
Dmitry Opokin
9d37b7cdf2
Add MediaTek md1img and GFH firmware image parsers (#5974)
- Introduced md1img.h and md1img.c for parsing MediaTek md1img container format.
- Implemented mtk.h and mtk.c for parsing MediaTek GFH firmware images (md1rom).
- Added plugin support for md1img and mtk formats in bin_md1img.c and bin_mtk.c.
- Updated meson.build to include new source files and plugins.
- Enhanced RzBuffer utility with LZMA alone decompression support.

---------

Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com>
2026-06-22 20:25:48 +00:00
Rot127
0599c98e76
Add hint for -F, if multiple bin plugins can load the binary. (#6548) 2026-06-22 11:24:46 +00:00
NOT XVilka
62bcb8f6fc
librz/bin: add STABS format parser (#6511)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-17 04:13:23 +08:00
billow
0421f03afe
Fix bin hunk/smd plugin ownership leaks (#6515) 2026-06-16 15:45:53 +00:00
Anton Kochkov
f89e09f6bc bin/coff: honor load addresses for TI linked (F_EXEC) executables
For a fully linked TI COFF executable the section s_vaddr fields hold the real
load addresses (e.g. .text at 0x100, vectors high) rather than a packed
sequential layout. Map sections at s_vaddr for F_EXEC objects (keeping the
sequential 16-aligned fallback only for relocatable objects), treat a defined
symbol's n_value as an already-absolute address instead of re-basing it onto the
section VA, and give non-loadable sections (DWARF/debug, build attributes,
.pinit) no loadable vaddr so their code-valued debug entries no longer split
instructions mid-stream or shadow the real low-addressed loadable sections. The
formats/coff test expectations are updated accordingly.
2026-06-15 23:31:05 +08:00
NOT XVilka
323e707114
librz/bin/elf: improve ARM Thumb symbols detection (#6502)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-14 17:25:00 +08:00
NOT XVilka
f832acdb5d
librz/bin: handle PLT sections properly (#6499)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-13 02:20:41 +08:00
Dmitry Opokin
423576676b
librz/arch: MIL-STD-1750 ISA support (#6042) 2026-06-11 12:53:58 +08:00
Giovanni
067b59f5ee
Fix rust lang detection (#6493) 2026-06-10 18:41:50 +08:00
NOT XVilka
fb9b15eac6
Fix pre-existing memory leaks in ObjC class and winkd module handling (#6471)
bin/dyldcache: dyldcache_classes() built the classes vector with
rz_pvector_new(free) and the per-class methods/fields lists with
rz_list_new() (no element destructor). Each RzBinClass was therefore
plain free()'d without releasing its name, methods and fields, leaking
memory.

debug/dmp (winkd): rz_debug_dmp_init() obtained the module list from
winkd_list_modules() in the non-triage branch, scanned it for
ntoskrnl.exe and then never freed it, leaking the list and all of its
WindModule entries.

Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-09 12:24:12 +08:00
NOT XVilka
940292aaae
librz/bin/pdb: fix memory leaks of PDB callable convention strings and orphaned callables (#6468)
Leak A - calling-convention string leaked
Leak B - orphaned callables on duplicate names

Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-06-09 12:23:56 +08:00
NOT XVilka
7e42c9a4d7
bin/elf: do not disassemble allocated string tables (.dynstr) as code (#6436)
The ELF section classifier in sections_obj() only marked a section as
data when its name contained "data". As a result .dynstr (type
SHT_STRTAB, SHF_ALLOC) was flagged neither as data nor as containing
strings, so is_data_section() rejected it. Two problems followed:

  - the string search (iz, and the default AUTO scan used by -A) skipped
    .dynstr, so its strings were never listed (only izz, which scans the
    whole file regardless of section flags, showed them);
  - because no RZ_META_TYPE_STRING metadata was applied over the region,
    the disassembler rendered the NUL-terminated symbol names as code,
    e.g. on MIPS "_GLOBAL_OFFSET_TABLE_" decoded to bgtzl/ldr/jalx/...

Mark a section as containing strings when it is mapped into memory
(SHF_ALLOC) and is either a string table (SHT_STRTAB) or carries the
explicit SHF_STRINGS flag. The SHF_ALLOC restriction keeps the loaded
string tables (.dynstr) while leaving the non-allocated .strtab and
.shstrtab to izz, matching the "iz lists the loaded image" semantics.

This is architecture independent; MIPS was simply where the bad
disassembly was first noticed.

Closes #5182

Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-05-31 04:01:21 +08:00
NOT XVilka
e6e3ca6abf
Rewrite the pf parser and rework the grammar (#6410)
* librz/type: rewrite pf format parser

Replace the legacy print-format engine in librz/type/format.c with a
clean three-stage pipeline (parse -> read -> render) and a properly
typed DSL.

The new pipeline:

  rz_pf_parse(str)                source string -> RzPfFormat
  rz_pf_read(fmt, buf, len, ctx)  RzPfFormat   -> RzPfValue[]
  rz_pf_render(vals, mode, opts)  RzPfValue[]  -> printable string

  rz_pf_format()                  one-shot for all of the above

Public API lives in <rz_pf.h> (pulled in transitively via <rz_type.h>).

DSL improvements over the legacy scheme:

  * Sized integers with explicit endianness via case:
    x4 d4 u4 o4 b4 (LE) vs X4 D4 U4 O4 B4 (BE).
  * Sized floats: f2 / f4 / f8 (and BE F2 / F4 / F8).
  * Encoding-aware strings: z(utf8) / z(utf16le) / z(utf16be) /
    z(utf32le) / z(utf32be) / z(latin1) / z(ebcdic).
  * Length-prefixed strings: z[N] reads a N-byte LE prefix then body.
  * Parameterized timestamps: t(unix32) / t(unix64) / t(unixms) /
    t(unixus) / t(unixns) / t(filetime) / t(dos) / t(hfs) /
    t(oletime) / t(webkit) / t(cocoa). ntfs alias maps to filetime.
  * GUID: G(ms) (Microsoft mixed-endian, default), G(be), G(le).
  * Inline bitfields: B4(FLAG_A=1,FLAG_B=2,FLAG_C=4).
  * Alignment: @N advances to next multiple of N.
  * Bit fields: :N with optional <  (LSB-first) or >  (MSB-first).
  * Length-by-reference arrays: [@earlier_field]T.
  * TLV records: V(t=u1,l=u2,e=le,h=v|l|a,d=table). Dispatch table
    uses tlv.<name>.<hex-tag> in the typedb formats hash.

Architecture highlights:

  * Per-instance ReadState (bit_cursor + sibling lookup window).
    The bit cursor snap-flushes to the next byte when a non-bit
    field follows mid-byte.
  * Recursion bound via RzPfCtx::max_depth (default 32).
  * Five render modes: text (default), json, cstruct, quiet, dot.
    The dot renderer emits a column-aligned record with offset/type/
    name/value rows, suitable for direct rendering through Graphviz.
  * Positioned diagnostics: RzPfError carries severity, category,
    column position, and a human-readable message. Each is also
    emitted via RZ_LOG_WARN for backward compatibility.
  * Optional RzPfPalette and RzPfRenderOpts threaded through render
    for inline ANSI colorisation. NULL palette = canonical text.
  * Pointer dereference via RzPfCtx::read_at callback.

The integration test expectations in test/db/cmd/cmd_pf* are
updated in the same commit to match the new text-output format and
the new DOT renderer's column-aligned record layout. Bundling these
keeps the test suite green at this commit.

A transitional rz_type_format_data() shim at the bottom of
pf_parser.c forwards legacy callers (cprint.c, disasm.c) to the new
API; it is removed in the librz/core migration commit.

* librz/arch/types: migrate type DB to new pf format codes

Map every legacy single-character format code in the bundled type
SDB files to its new-DSL equivalent:

  b / C  ->  x1     (1-byte hex)
  c      ->  c      (signed char, unchanged)
  w      ->  x2     (2-byte hex LE)
  i      ->  d4     (signed 32-bit decimal LE)
  d      ->  x4     (4-byte hex LE)
  q      ->  x8     (8-byte hex LE)
  f      ->  f4     (32-bit float LE)
  F      ->  F8     (64-bit float BE)
  Z      ->  z(utf16le)
  x      ->  x4
  o      ->  o4
  X      ->  r      (hexdump)
  n / N  ->  d4 / u4

Also add new typedef-only types for explicit display formats:

  bin{8,16,32,64}_t  ->  b{1,2,4,8}    (binary)
  hex{8,16,32,64}_t  ->  x{1,2,4,8}    (hex)
  oct{8,16,32,64}_t  ->  o{1,2,4,8}    (octal)

These let users opt into a display representation per field without
changing the underlying scalar size.

Update the corresponding integration test expectations in
test/db/cmd/cmd_avg and test/db/cmd/types: the 'tu', 'tuc', 'tp',
and 'avgp' commands report formats via the SDB, so the migrated
codes appear in their text output (e.g. 'pf 0f4x4 a b' instead of
the legacy 'pf 0fd a b' for a union of float + int).

* librz/core: rewrite pf integration on the new parser API

Remove the legacy rz_type_format_data() bridge and rewrite every
caller to use the new <rz_pf.h> API directly.

librz/core/cprint.c

  core_print_format() constructs an RzPfCtx populated from the
  RzCore (typedb, big_endian, bits, max_depth) and calls
  rz_pf_format() in one shot. The bridge between RzCore I/O and the
  pf reader is cprint_pf_read_at(), which forwards to rz_io_nread_at.
  The bitmask-to-RzPfMode mapping is cprint_pf_mode().

  For DOT mode the format name is passed via RzPfRenderOpts::graph_label
  so the dot renderer uses it as the top-level record label.

  When scr.color > 0 in TEXT mode, an RzPfPalette is populated from
  the active color theme via RzConsPrintablePalette so `pf` output
  blends with the rest of Rizin's UI and respects user theme
  choices (eco / ec). The palette slots map to theme fields as:

    pf field offset       <- pal->offset    (address column)
    pf field name         <- pal->fname     (symbolic name)
    pf endian marker      <- pal->meta      (metadata tag)
    pf hex/number literal <- pal->num       (numeric literal)
    pf typedb label       <- pal->flag      (resolved symbol)
    reset                 <- pal->reset

  Each slot falls back to its previous hardcoded ANSI escape if the
  theme field is unset, preserving prior behaviour for stripped-down
  contexts. Other modes (json/cstruct/quiet/dot) ignore the palette.
  Closes rizinorg/rizin#782.

librz/core/disasm.c

  RZ_META_TYPE_FORMAT case rewritten to resolve via rz_pf_resolve_name
  and decode via rz_pf_format() directly. Palette is supplied from
  the same theme palette when ds->show_color is true so that
  pd @ <struct> blends with the surrounding listing.

librz/include/rz_type.h

  Drop the rz_type_format_data() forward declaration. Callers must
  use the public <rz_pf.h> surface instead.

librz/core/cmd_descs/cmd_print.yaml

  Rewrite the pf command help for the new DSL: sized integers
  (case-discriminated endian), special scalars (G GUID, V TLV,
  : bits, @ align), strings with encodings, parameterized timestamps,
  typed composites (E enum, B bitfield, ? struct), DSL extensions
  (length-prefix strings, length-by-reference arrays, inline
  bitfields), skip/repeat/pointers, example invocations.

  cmd_descs.c is regenerated from the YAML.

* test: pf parser unit and DSL-extension integration tests

Add fresh test coverage for the new pf parser. These are purely
additive: existing integration tests were updated in the parser
and SDB-migration commits so the suite stayed green throughout.

test/unit/test_pf.c (new, 131 tests)

  Field-size tables (every fixed-size type) and ctype mapping, every
  parse path (sized integers / floats / strings / timestamps /
  pointers / structs / enums / bitfields / GUIDs / TLV / alignment /
  bits / arrays), every read path (with both fixed and length-by-
  reference array counts), every render mode (text / json / cstruct /
  quiet / dot), every DSL extension (align, bits MSB/LSB, GUID layout,
  length-ref array, length-prefix string, inline bitfield, TLV with
  dispatch table), pointer dereference via an in-memory I/O callback,
  recursion safety on self-referential structs, lifecycle / NULL
  safety, diagnostics (positioned errors, all categories, caret-line
  formatter, source capture, verbose parse), ambiguity (each
  superficially similar DSL form parses unambiguously), the palette /
  colorisation API (issue #782) including a regression test surfaced
  by the property-based test harness for input bytes containing ESC,
  and DOT-mode coverage (column-aligned layout, single field,
  empty/filtered, timestamp values, TLV records).

test/db/cmd/cmd_pf_dsl (new)

  8 integration tests targeting the new DSL extensions specifically:
  @N alignment, :N bits in MSB and LSB ordering, default-layout GUID,
  z[N] length-prefixed string, B4(K=V) inline bitfield, bare V TLV
  with defaults, V(t=u2,l=u2,e=be) configured TLV.

test/db/cmd/types_format (new)

  Verifies that the new bin{N}_t / hex{N}_t / oct{N}_t typedefs apply
  the expected display representation when used inside struct fields
  via the 'tp' command, demonstrating the per-base rendering
  (binary / decimal / octal / hex).

* doc: pf DSL reference and librz/type README

doc/pf.md (new)

  User-facing reference for the pf format DSL covering quick
  examples, spec grammar (sized integers with case-discriminated
  endian, floats, strings with encodings and length prefixes,
  parameterized timestamps, composites -- struct ?, enum E, bitfield B
  inline and typed, GUID G, TLV V, raw hexdump r), repetition and
  arrays ([N], [@name], {N}, leading 0 for union), padding and
  alignment (. skip, @N align, :N bits MSB / LSB), pointer
  dereference (*<type>), names grammar (plain vs (typename)name),
  output modes (text, json, cstruct, quiet, dot), and diagnostics
  (severity / category / position / caret-line formatter; backward-
  compatible RZ_LOG_WARN channel).

librz/type/README.md (new)

  Subsystem architecture doc for librz/type. Covers public headers,
  file map, the pf three-stage pipeline (parse -> read -> render) with
  a diagram and entry-point table, per-stage explanations (parser
  shape, ReadState scoping rules including bit cursor and sibling
  lookup window and snap-flush rule, render mode dispatch including
  the DOT column-aligned layout and the graph_label parameter),
  typedb integration and recursion bound, error-reporting model,
  test coverage summary, and pointer to doc/pf.md as the user-facing
  reference.

* librz/type: remove legacy DSL conversion shim

All in-tree callers -- librz/bin/d/, librz/bin/format/, and the
integration tests in test/db/cmd/ -- have been migrated to the new
DSL in the earlier commits of this series. The compatibility shim
that translated bare legacy specifiers (x -> x4, b -> x1, w -> x2,
nN -> uN, NN -> UN, etc.) into the new DSL at the entry of
rz_pf_parse() is no longer load-bearing; this commit deletes it.

  - librz/type/pf_parser.c: drop the 267-line
    convert_legacy_to_new_dsl() function, the WARN_LEGACY macro,
    and the per-parse allocation + free of the converted string.
    rz_pf_parse() now walks the caller's spec directly.
  - test/db/cmd/cmd_pf,cmd_pf2,cmd_pf_write,cmd_pfd,cmd_pf_new,
    metadata: migrate legacy specifiers in CMDS blocks to the new
    DSL (b -> x1, w -> x2, q -> x8, i -> d4, bare x -> x4, etc.)
    and regenerate EXPECT blocks against the new render where
    affected.

The parser now only accepts the new DSL. Any caller still passing
bare legacy specifiers will get "unknown specifier" warnings.

* librz/core,type: add scr.pf.short for delta-offset rendering

When scr.pf.short is enabled, MODE_TEXT rendering shows offsets as
deltas (+<n>) from the format's base address instead of the absolute
hex address. Useful for self-contained struct dumps where the
absolute load address is noise:

  $ rizin -e scr.pf.short=true -qc 'wx 00007a452a4b9a02
                                    pf fcb1d4 a b c d' =
     0 : a = 4000 [LE]
    +4 : b = '*'
    +5 : c = 0b0100_1011 [LE]
    +6 : d = 666 [LE]

Nested structs reset their delta from the same base, so a child of
`head` at offset +8 still prints as +0 in its own struct block.

The base is derived from the offset of the first top-level value;
callers can override it via RzPfRenderOpts::base_offset.

Includes 5 integration tests in test/db/cmd/cmd_pf_short covering
basic struct, off-mode parity (control), nested struct, concatenated
TLV records, and @-offset usage.

* librz/type,test,doc: add v(N) bitvector type for forensics use

Adds a new specifier `v(N)` to the pf DSL that reads N individual
bits (1..4096) from `ceil(N/8)` bytes and exposes them as N
separate 0/1 scalars. Forensics targets: page-frame bitmaps, NTFS
$Bitmap clusters, ext4 block/inode bitmaps, ELF DT_FLAGS_1, PE
characteristics, ACL bitmasks -- anywhere you want to *see* a
bitmap rather than collapse it to a hex number.

Grammar:
  v(N)        N-bit bitvector, default MSB-first per byte
  v(N,lsb)    LSB-first per byte (Intel order)
  v(N,msb)    explicit MSB-first (DWARF / network order)

Rendering:
  text:    [ 1 0 1 0 1 0 1 1 | 1 1 0 0 ] (12-bit)
  json:    {"bit_width":12,"value":"101010111100"}
  quiet:   1 0 1 0 1 0 1 1 1 1 0 0

Bitvec fields do not participate in the packed-bit cursor used by
:N; each v(N) reads whole bytes and stands alone. A v(N) field
adjacent to a :N field flushes the partial bit cursor first.

Width is clamped to [1, 4096] with a RANGE diagnostic. The reader
consumes exactly ceil(N/8) bytes, leaving the cursor positioned for
the next field. Verified by the existing tail-field test pattern.

Tests:
  test/unit/test_pf.c        +10 unit tests (146 total OK)
  test/db/cmd/cmd_pf_new     +9 cmd tests  (440 OK / 9 BR / 0 XX / 4 FX
                                            across all 19 pf suites)
  property harness           +7 properties (140 unique props, 1000
                                            trials each, 0 failures)

Docs:
  doc/pf.md                  bitvector section with examples
  librz/type/README.md       cursor-interaction note for v(N) vs :N

* librz/core,type,test: address PR CI feedback for pf rewrite

Five fixes prompted by CI feedback and reviewer comments on the pf
rewrite series:

* librz/core/cmd_descs/cmd_print.yaml: two help-text lines exceeded the
  yamllint 120-char ceiling (n1/n2/n4/n8 comment and the deprecation
  notes entry). Both now use the same folded-scalar (comment: >) form
  already used in cmd_analysis.yaml and cmd_descs.yaml. cmd_descs.c is
  regenerated.

* test/db/cmd/cmd_pf_write: drop the BROKEN 'pf xxd print' test. It
  relied on '.pf*' (run pf output as rizin commands) which the new
  parser no longer emits -- analogous to the '.pfw' removal done
  earlier. The companion 'pf xxd print happy' test exercises the same
  path through 'pf.' and stays.

* librz/type/pf_parser.c: thread the RzTypeDB through render_cstruct
  and render_dot (and their inner helpers) so RZ_PF_ENUM resolution
  works in pfc and pfd mode the same way it already does in text mode.
  Without this, 'pfc elf_header' emitted '/* 0x00000002 */' and 'pfd'
  emitted '|value|0x0000ffff|'; with it the comments and cells carry
  the symbolic name (ELFCLASS64, ET_HIPROC, etc).

  scalar_text() RZ_PF_BITFIELD: when no inline B4(K=V,...) flags are
  present but val->type_name names a typedb enum, walk that enum and
  treat each case as a settable bit name. This makes the typedb form
  'B (pe_characteristics) flags' decode to
  '0x00008140 : IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | ...' instead
  of just the raw hex -- previously the bitname decoding only worked
  on inline B4(...) forms.

* librz/core/cprint.c: cprint_pf_mode() had no mapping for
  RZ_PRINT_VALUE, so 'pfv' fell through to TEXT mode and emitted
  '0x00000004 = 0x11111111 [LE]' instead of the bare value '0x11111111'
  expected by db/esil/arm_16 and existing pfv users. Added an explicit
  RZ_PRINT_VALUE -> RZ_PF_MODE_QUIET mapping; QUIET already emits one
  bare scalar per field, which is exactly the pfv contract.

* test EXPECTs: cmd_pfd unbreaks its bitfield case (also fixes the
  data buffer -- the original used 'wx 0x00008140' which is parsed
  byte-by-byte and yields LE u32 0x40810000, not 0x00008140, so no
  flags matched). cmd_pf 'PE test' picks up the now-decoded
  characteristics and dllCharacteristics bitfields. cmd_pf 'Print
  value only' updates to the bare-value pfv contract. test/db/cmd/print
  'elf 64bit ls pfc.elf_header' picks up the decoded enum symbols.

Also picks up clang-format-20 reflows in cprint.c, cmd_print.c,
pf_parser.c, and rz_pf.h that the CI's clang-format check flagged.
Also bumps the offset-delta buffer in render_val_text from 16 to 24
bytes so a worst-case ut64 decimal (20 digits + sign + NUL = 22) fits
without tripping -Werror=format-truncation on gcc with -O0.
Also fixes three swapped-argument mu_assert calls in test_pf.c (the
v(N) bitvector tests added in commit 8): the macro signature is
mu_assert(message, test) but those three calls passed (test, message),
which tripped -Werror=format= under -O3 because the int 'test' was
fed to the format string's %s slot.
Adds a second round of regression fixes prompted by a manual audit
against pristine upstream (review feedback after the first pass):

* render_quiet: handle raw byte-sequential types (RZ_PF_UINT128,
  RZ_PF_HEXDUMP). scalar_text() has no per-byte case for these so the
  default-clause '?' was emitted, making 'pfq Q' and 'pfv Q' print '?'.
  render_quiet now mirrors text mode and emits a space-separated hex
  stream for raw types.

* Sized pointers (p{2,4,8}): the legacy parser accepted 'p2', 'p4',
  'p8' to force a 16/32/64-bit pointer width regardless of ctx.bits;
  the new parser only handled bare 'p'. Restored via a new dispatch
  branch ahead of bare 'p', recording the override in
  RzPfField::bit_width (overloaded -- documented in rz_pf.h). A new
  fld_ptr_size() helper consults the override first; read_ptr, the
  pointer-deref read path, the STRPTR read path, and
  pf_struct_size_impl all use it. 'pf p2p4p8pp2' now consumes
  2+4+8+4+2=20 bytes and renders the right value at each position.

* Numeric pointer dereference: '*d4', '*x2', '*u8', etc. (pointer to
  fixed-size scalar) only read the pointer itself and never followed
  it. The reader now also calls ctx->read_at to fetch the target word
  and populate scalars[0]; the text renderer prints both the pointer
  literal and the dereferenced value -- '(*0x20) 42' instead of bare
  '(*0x20)'. Affects 'pf *d4 ...' and the 'Pointers' / '32 bit twice
  then string' tests.

* Pointer-to-struct dereference (*?): pointer-to-struct fields read
  the pointer value but stopped there, so 'pf *?' (or typedb forms like
  '(troll)Bah' marked with '*') showed only '(*0x30)'. The reader now
  recurses through ctx->read_at into a worst-case 4 KiB buffer and
  re-invokes read_nested_struct; the renderer prints the nested struct
  body after the '(*ptr)' annotation. Recursion is bounded by
  ctx->max_depth so cyclic Bah->Bah pointer chains terminate at the
  documented limit instead of unbounded recursion. Affects 'nested
  struct', 'complex nested struct', and 'flag for nested struct'.

* String pointer (bare 's'): RZ_PF_STRPTR rendering didn't show the
  dereferenced target -- output was bare '"hello"' with no pointer
  context. Now emits '(*ptr) "string"' (mirroring '*z') when the
  deref produced a non-empty body; falls back to bare '""' on
  unmapped or empty targets to avoid advertising a phantom pointer.

* render_val_text is_pointer branch: extended to render the nested
  struct body for *? pointers and the dereferenced value for numeric
  *d4/*x2/*u8 forms.

* Top-level read loop: rz_pf_read passed both 'cur_off + off' (as
  read_field's off parameter) AND 'base_addr + cur_off' (as base_addr),
  but read_field computes 'val->offset = base_addr + off'. This
  double-added cur_off on every iteration past the first, so 'pf 2ic'
  reading 5 bytes per iter reported iter 1's nb at offset 0x0a instead
  of 0x05, and 'pf 2F' reported iter 1's double at offset 0x10 instead
  of 0x08. Data reads were correct; only the displayed/JSON offsets
  drifted. The fix: pass base_addr unchanged so val->offset becomes
  base_addr + (cur_off + off). Affects 'array obj', 'print n-times a
  format', 'pf', 'pf field name', 'JSON output'.

* Bare 'C' (legacy 1-byte unsigned decimal): the legacy parser accepted
  'C' as 'print byte as decimal'; the new parser had dropped it. The
  'types' test format 'pf fcb1d4C foo bar fool beer plop' was therefore
  truncating to 4 fields. Restored as a deprecated alias for 'u1' (with
  the standard 'use u1' note).

* pfw dotted-path navigation: the write-mode lookup only matched
  top-level field names, so 'pfw gobelin.Buh.first=42' through nested
  structs failed with 'field not found'. Replaced with a segment-by-
  segment walker that descends through children at each dot. Affects
  'write specific element through nested struct'.

* Drop '.pfw' usage from tests. '.pfw' (execute pfw output as rizin
  commands) was a legacy convention -- the new pfw writes directly via
  rz_io_write_at and emits a human-readable confirmation line, so the
  '.' prefix evaluates that confirmation line as a command and fails.
  Same direction as the earlier '.pf*' removal. All cmd_pf,
  cmd_pf_write, cmd_pf2 tests updated.

* test/db/cmd/cmd_pf 'Register' marked BROKEN with a tracking comment:
  the legacy 'r (regname)' looked up CPU registers via
  RzPrint::get_register; the new parser repurposes 'r' as raw hex byte
  dump and the register-fetch path is gone. Restoring would mean
  wiring a new register-lookup hook through RzPfCtx, which is outside
  the parser-rewrite scope.

* test/db/cmd/cmd_pf2 'pf F max precision (#13027)' annotated: not a
  precision regression. Values differ from the original #13027 expected
  output because the legacy 'F' specifier read bytes as LE-then-
  reinterpret while the new parser follows the documented 'UPPERCASE
  = BE' rule literally; the 17-digit precision -- the actual subject
  of #13027 -- is preserved.

EXPECTs updated to match the corrected output across cmd_pf, cmd_pf2,
cmd_pf_write.
* doc/pf.md updated to reflect all DSL and rendering changes:
  documents the sized pointers (p/p2/p4/p8), pointer dereference
  semantics (numeric, struct, and string), the missing composites
  (Q, U, L, n/N), the case-as-endian rule (no standalone endian
  directive), the pfw write mode (dotted-path navigation, direct I/O,
  no '.pfw'/'.pf*'), and the table of deprecated single-letter
  aliases (b, d, o, q, u, i, f, F, w, Z, t, T, X, C).
* librz/type/pf_render.c (new): extracted the render-mode code paths
  from pf_parser.c into their own translation unit. Hosts the text /
  quiet / JSON / cstruct / DOT renderers, the per-mode helpers
  (scalar_text, scalar_json, render_binary, render_guid,
  compute_name_width, field_matches, emit_colored*), the RenderCtx
  bag, and the public rz_pf_render() + rz_pf_render_json() entry
  points. pf_parser.c keeps the parse + read pipeline and shrinks
  from 4831 to 3280 lines. Helpers used by both translation units
  (is_string_type, is_raw_type, endian_str, pf_vasprintf) move to
  pf_parser.h as static inlines.
* librz/type/pf/ (new directory): moved every pf source out of the
  librz/type/ top level into a dedicated pf/ subdirectory; only the
  legacy format.c stays top-level. meson.build updated with the new
  paths and the pf/ include dir.
* Split the monolithic parser into focused sub-grammar TUs, wired
  together by the new pf/pf_internal.h (which centralizes the PF_DIAG
  diagnostic macro, the shared ReadState, and all cross-TU
  declarations):
    - pf_parser_string.c   string/encoding specs (z / s / Z)
    - pf_parser_bitfield.c inline + typed bitfields
    - pf_parser_bitvec.c   bitvectors v(N)
    - pf_parser_array.c    array-count resolution
    - pf_parser_struct.c   nested struct / union reading
  pf_parser.c shrinks from 3280 to ~2620 lines and now hosts only the
  parse driver, type-spec dispatcher, reader core, context, and the
  public utility surface. The TLV TU was migrated off its bespoke
  extern/TLV_DIAG block onto the shared header.
* Add an RzStructuredData renderer: pf/pf_render_sd.c with the public
  rz_pf_render_sd() (declared in rz_pf.h). (Named _sd, not _sdb: SDB is
  Rizin's key/value database, unrelated to RzStructuredData.) It maps the decoded value
  vector to the generic key/value document model -- scalars to typed
  entries, arrays/bitvectors to arrays, nested structs to sub-maps
  with a _type tag, raw/GUID payloads to byte blocks, timestamps to a
  formatted string plus a <name>_raw sibling -- so callers get JSON,
  YAML, or iterator access for free. Unit and property tests cover it
  (see the consistency-pass note below).
* doc/pf.md and librz/type/README.md updated for the new pf/ layout
  and the structured-data render mode.

* Consistency pass over librz/type/pf/: deduplicated the structured-data
  scalar dispatch (one classifier feeding thin map/array emitters instead
  of two parallel ~60-line switches), dropped unused includes
  (pf_parser_time.h from the TLV TU, string.h from the struct TU,
  rz_endian.h from the SD renderer) and a redundant extern decl now
  covered by pf_internal.h, and fixed a dangling-pointer bug in the SD
  char path (the classifier returned a pointer into its own by-value
  temporary). Expanded coverage: 11 SD unit tests (157 total) and 6 new
  theft properties (SD tree non-NULL, JSON structural well-formedness,
  top-level object shape, YAML safety, determinism, filter-narrows).

* Split pf_render.c (1548 lines) into per-mode renderer TUs, mirroring
  the earlier pf_render_sd.c extraction: pf_render_text.c (text+quiet),
  pf_render_json.c (+rz_pf_render_json), pf_render_cstruct.c, and
  pf_render_dot.c. A new pf_render.h carries the shared RenderCtx record
  plus the cross-TU helper (pf_field_matches, pf_scalar_text,
  pf_render_guid) and per-mode entry-point declarations. pf_render.c now
  holds only those shared helpers and the rz_pf_render() dispatcher
  (~372 lines). meson.build, the file-doc layout listings, and
  librz/type/README.md are updated accordingly.

* Second consistency pass: ensured every public RZ_API entry point has a
  Doxygen \brief block (added ones for rz_type_format_struct_size and
  rz_pf_render_sd) and every file a \file description (added to
  pf_parser.h and pf_parser_time.h). Deduplicated the field-size logic:
  pf_struct_size_impl's sum and union loops now share one
  pf_field_static_size() helper, the enum/bitfield byte-width override is
  a single pf_enum_bitfield_width() helper (was inlined 3x), sized-pointer
  width routes through the existing fld_ptr_size(), and the inline-bitflag
  test shared by the JSON and DOT renderers became the
  pf_value_has_inline_bitflags() predicate in pf_render.h. Dropped unused
  includes left over from the render split. No behaviour change (157 unit
  tests, 146 theft properties, full cmd sweep all green).

* Fix a CodeQL High alert (cpp/integer-multiplication-cast-to-long) in
  the scalar-array path selector: the per-element byte delta was computed
  as `idx * width` in 32-bit int before being added to the ut64 offset,
  so a large array index could overflow int prior to the widening. The
  multiplication is now done in ut64 ((ut64)idx * width). No behaviour
  change for in-range indices; verified by the path-selection cmd tests.

* Fix a big-endian bug in the structured-data renderer: the bitvector
  reader stores each bit in the RzPfScalar union's v_u8 member, but the
  SD classifier read it back through v_u64. On little-endian those alias
  to the same low byte so it worked by luck; on big-endian (s390x) v_u8
  is the high byte of the 64-bit slot, so every set bit read as a large
  number and the test_pf_render_sd_bitvec assertion failed. The
  classifier now reads v_u8 for RZ_PF_BITVEC, matching the writer; the
  other scalar types already read the same width the reader wrote.
* Clean up leftover refactoring-era comments in the renderer TUs: drop
  the "Split out of pf_render.c" changelog phrasing from the file-doc
  headers (the docs now describe the current layout) and update two
  stale references to the pre-rename helper names (field_matches ->
  pf_field_matches, render_guid -> pf_render_guid) in comments.

---------

Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-05-29 03:58:58 +08:00
Anton Kochkov
d81489e40d bin/dwarf: force big-endian read on TMS320 COFF DWARF sections
TI's cl55 compiler writes COFF files with little-endian file and
section headers, but the data inside DWARF sections (.debug_info,
.debug_abbrev, .debug_frame, .debug_line) is laid out as 16-bit
big-endian words. The DWARF parser was reading the unit length as
LE and getting absurd values, then bailing out with zero
compilation units.

Result: afvl, avgl, afs all returned empty for every
emulateme*.ticoff2.dbg.coff in rizin-testbins even though the
file had a fully-populated .debug_info section, the abbrev
tables parsed cleanly, and the per-architecture DWARF register
mapping (added separately) was available.

Override bf_bigendian() for arch=tms320 so the DWARF endian reader
swaps correctly. The COFF info struct stays in the same
little-endian state it always was; only the dwarf reader's view
flips.

After this fix, cl55-compiled TI COFF v2 binaries with debug info
yield:
  afvl @ dbg.main  -> arg int argc @ ar4
  afs  @ dbg.main  -> int main(int argc);
  avgl             -> 7 globals (uart_address, seckrit, _lock, ...)
  pdf  @ <fn>      -> renders with signatures, named args, reflines,
                      resolved call targets
2026-05-28 17:44:54 +08:00
Anton Kochkov
64c1cad7e5 bin/coff: promote globals in code sections to FUNC
COFF C_EXT (external/global) symbols carry their function-or-not
status in two places: the DTYPE field of n_type (the ISFCN bit), and
implicitly by the section they live in. The existing code only
honoured the DTYPE bit:

  ptr->type = DTYPE_IS_FUNCTION(s->n_type) || !strcmp(name, "main")
      ? RZ_BIN_TYPE_FUNC_STR : RZ_BIN_TYPE_UNKNOWN_STR;

C and C++ compilers set the ISFCN bit when emitting object code, so
this works for compiled output. But assembler-emitted globals -- TI's
asm55p / cl55, the GNU GAS COFF backend on legacy targets, and any
hand-written .s -- often leave n_type at zero. Every assembly symbol
then comes back as RZ_BIN_TYPE_UNKNOWN_STR, and 'aaa' has no way to
distinguish a function from a data label. Concrete example: with TI
asm55p output for the C55x+ test corpus, none of the eight .global
labels in 03_branches_calls.s (_short_ret, _short_branch, _short_call,
...) were promoted to functions, so analysis only found those
reachable by following control flow from a hard-coded entry.

Add a section-flag fallback: if the symbol's containing section has
COFF_SCN_CNT_CODE set (i.e. it's a .text / code section), the symbol
is a function. This keeps the DTYPE check as the primary signal but
fills the gap on assembler output.

Verified with TI C55x+ .obj files: all .global labels now appear as
RZ_BIN_TYPE_FUNC_STR and are picked up by 'aaa'. No regression on
the standard COFF test suite (Windows i386/amd64 .obj from compiled
C output).
2026-05-28 17:44:54 +08:00
Anton Kochkov
88a4121d70 bin/coff: support TI COFF v2 48-byte section header
The COFF section table walker assumed every COFF section header is
40 bytes -- the standard COFF1 form. The TI Common Object File Format
(SPRAAO8) extends this for TI COFF v2 (file magic 0x00C2) used by the
TI tools (asm55, cl55, cl6x, cl28, etc.):

  ------------------------------------------------------------------
  offset  size  field         standard COFF1     TI COFF v2
  ------------------------------------------------------------------
  0x00    8     s_name        char[8]            char[8]
  0x08    4     s_paddr       ut32               ut32
  0x0c    4     s_vaddr       ut32               ut32
  0x10    4     s_size        ut32               ut32
  0x14    4     s_scnptr      ut32               ut32
  0x18    4     s_relptr      ut32               ut32
  0x1c    4     s_lnnoptr     ut32               ut32
  0x20    2/4   s_nreloc      ut16               ut32  <-- widened
  0x22    2/4   s_nlnno       ut16               ut32  <-- widened
  0x24    4     s_flags       ut32               ut32
  0x28    -     reserved      -                  ut16  <-- new
  0x2a    -     mempage       -                  ut16  <-- new
  ------------------------------------------------------------------
  TOTAL          40                              48

Reading TI COFF v2 with the standard 40-byte stride walks the section
table off-by-8 per section, producing nonsense values for every
section after the first. In practice, vaddr and size for the second
section spill into the next section's name field, surfacing as
attention-grabbing decimal values like 0x7461642e (ASCII '.dat'
reversed -- bytes from the upcoming '.data' name being interpreted as
a size).

Concrete reproducer with TI asm55p output:
  $ wine asm55p.exe -v5505 03_branches_calls.s
  $ rz-bin -S 03_branches_calls.obj                # before this fix
  ...
  0x00000061 0x7461642e 0x00000040 0x7461642e ...  # garbage size
  ...
  $ rz-bin -S 03_branches_calls.obj                # after this fix
  0x000000fa       0x34 0x00000030       0x34 -r-x .text
  ...

Fix: add a parallel coff_init_scn_hdr_ti() that reads the 48-byte
layout, with nreloc/nlnno as ut32 (clamped to ut16 because the rest
of the COFF code keeps them as 16-bit and counts above 64K are not
encountered in practice). bin_coff_init_scn_hdr() picks the variant
based on coff_is_ti_machine() -- the same predicate already used in
the file-header parser to consume TI's f_target_id field.

Tested with TI asm55p output for C55x, C55x+, and C5500 (machine ids
0x9c, 0xa1, and TI_1/TI_2 file magics) -- sections now parse with the
correct sizes, vaddrs, and flags, and the resulting binaries open
cleanly under 'rizin -A' for analysis.
2026-05-28 17:44:54 +08:00
Khairul Azhar Kasmiran
1abe2dce99
Prevent RzBuffer's Oxff_priv from overriding io.0xff (#6371)
* Prevent RzBuffer's `Oxff_priv` from overriding `io.0xff`
* Use io from RZ_BUFFER_IO and RZ_BUFFER_IO_FD buffers
* Add `RzIO *` param to rz_buf_new_mmap()
* pe: Discard incomplete import directory
2026-05-27 06:18:45 +08:00
Khairul Azhar Kasmiran
60f39e2df5
librz/bin/pe: discard incomplete section headers (#6397)
* PE: discard incomplete section headers
* Invert logic
2026-05-24 01:11:43 +08:00
SSharshunov
b2297073bf
librz/bin/omf166: fix format errors and if_fail macroses (PFMTSZu) (#6368) 2026-05-17 20:21:05 +08:00
SSharshunov
ee3e628c8a
librz/bin/omf166: fix format errors and if_fail macroses (#6362) 2026-05-16 21:06:31 +08:00
SSharshunov
5256726d00
librz/arch/c166: remove unnecessary use of assert macroses (#6345) 2026-05-15 23:53:27 +08:00
SSharshunov
e4976144c3
librz/bin/omf166: fix coverity issues (#6346)
* CID 909878
* CID 909868
* CID 909875
* CID 909860
2026-05-15 01:52:20 +08:00
well-mannered-goat
5dd20c43b5
librz/bin/elf: improve aarch64 relocs support (#6022) 2026-05-14 12:54:12 +08:00
Arya H R
9ce185e507
librz/arch/luajit: fix parsing on big-endian machines (#6350) 2026-05-14 12:53:19 +08:00
Giovanni
2d1cff75ee
librz/bin/elf: add some missing MIPS relocs (#6348)
* Add support to various MIPS reloc conversion.

R_MIPS_26, R_MIPS_HI16, R_MIPS_LO16, R_MIPS_GOT16, R_MIPS_PC16,
R_MIPS_CALL16, R_MIPS_64, R_MIPS_GOT_HI16, R_MIPS_GOT_LO16,
R_MIPS_CALL_HI16, R_MIPS_CALL_LO16, R_MIPS_REL16

* Fix test missing RUN at the end.
2026-05-14 00:52:59 +08:00
NOT XVilka
9db62b03fa
librz/bin/omf: OMF166 fix error handling (#6342)
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
2026-05-13 00:47:50 +08:00
Rot127
1750cc27fc
librz/bin/omf: fix build warning (#6341) 2026-05-13 00:47:23 +08:00
Arya H R
b09bdf2242
librz/arch: add LuaJIT 2.1 bytecode support (#5961)
* Add LuaJIT binary loader
* Add LuaJIT analysis and disassembly plugin
* New CPU format `luajit` for luac plugin
2026-05-12 23:37:10 +08:00
SSharshunov
ea370203ed
Support Siemens/Infineon C16x microcontroller (#6321) 2026-05-12 21:17:37 +08:00
Rot127
e6d0937c8a
Fix OOB read in OMF format plugin (#6336)
* Fix OOB read of section due to invalid bounds check.
* Move array offset to variable for readability.
2026-05-11 23:53:51 +08:00
SSharshunov
fe524a30e8
librz/bin: fix the false-positive detection of the C166 bins as AVR bins 2026-05-10 03:37:19 +08:00
billow
4e7c9af04c
Update capstone for M68k (#6309)
* Bump capstone to the latest next
* Add capstone M68k changes
* Update M68k instruction size and fix tests
* Add M68K assembly instruction definitions for 68000, 68020, 68030, 68060, and CPU32
* Update maxopsz to 22 for bflt, hunk, and smd formats
* Add M68k ELF coredump parsing support
2026-05-05 03:16:53 +08:00
well-mannered-goat
76a41c8166
Fetch the addends from the relocation position in REL types of object files (#6112) 2026-05-04 21:53:59 +08:00
Florian Märkl
bc22b44549 Replace strnlen calls
Non-C-standard strnlen is not available on Mac OS X 10.5
2026-05-04 06:22:00 +02:00
Khairul Azhar Kasmiran
af6dade945
elf: Simplify phdr checking code (#6302) 2026-05-02 18:53:53 +08:00
Khairul Azhar Kasmiran
c1e26fee02
librz/bin: add more ELF header warning detail (#6301) 2026-05-02 16:43:28 +08:00
Cheese Cake
a99cc738c2
util: extend string search with user-defined printable characters (#6161)
* util: extend string search with user-defined printable characters
* util: use RzVector for user_unprintable options
* util: address review for configurable unprintable chars
* core/cconfig: use goto error_free pattern in cb_str_unprintable
* test/cmd_search_z: merge duplicate Armenian utf16le tests
2026-05-01 22:47:14 +08:00
Mohammed Muqeet Us Salam
9007cde56e
librz/bin: fix regstate load in ELF corefiles for x86_64 (#6195)
* regstate retrieval in ELF corefiles
* remove rzbin call from cmd_debug
* increase FP_LAYOUT to 128
2026-05-01 12:07:59 +08:00
Giovanni
9d5dc6edd1
Cleanup luac code (#6298) 2026-04-30 16:57:47 +08:00
bubblepipe
dcc825da7b
librz/bin: ELF coredump parsing support for LoongArch (#6273) 2026-04-28 02:34:37 +08:00
bubblepipe
1ef81fb956
librz/bin: ELF coredump parsing support for s390x (#6271) 2026-04-27 22:22:08 +08:00