list_strings
list_strings returns every string that Ghidra defined as Data, which includes loader metadata and symbol fragments, and excludes any text Ghidra did not define.
You expect five labels and three format strings. list_strings returns 39 items, among them /usr/lib/dyld, _label, _, and an empty string. Each one is a real run of bytes in the file. The list is complete for what Ghidra defined, and it is only that.
When you finish this section, you can place each of the 39 strings in its load command. You can also say what an empty result does and does not prove.
The call
"name": "list_strings",
"arguments": {}
…
{
"address": "0x100000770",
"value": "F",
"string": {
"encoding": "US-ASCII",
"termination": "present_or_not_required",
"byte_length": 2
}
},
…
{
"address": "0x1000007cf",
"value": "",
"string": {
"encoding": "US-ASCII",
"termination": "present_or_not_required",
"byte_length": 1
}
},
…
{
"address": "0x1000080c7",
"value": "_label",
"string": {
"encoding": "US-ASCII",
"termination": "present_or_not_required",
"byte_length": 7
}
},
…
"limitations": [
…
"Only Ghidra-defined string Data is observed; packed or undefined string bytes may be absent. Completeness applies to that inventory, and an empty search does not establish that text is absent from the artifact. If an address is known, use read_bytes and xrefs to inspect bytes and references.",
"Charset is reported, while a non-missing terminator cannot distinguish a present terminator from a fixed or Pascal layout.",
…
],The bridge walks every defined data item in the program and keeps the ones with a string value. For each it records the charset, whether a required terminator is missing, and the byte length. Each item is a Data object that Ghidra's loader or analyzers created. A run of printable bytes that no analyzer turned into Data is not in the list. The first limitation is fixed in rea, and the docs say the same:
termination has two values. missing means a string type that needs a null byte has none. present_or_not_required covers everything else, because Ghidra cannot tell a present terminator from a layout that needs none. byte_length counts the terminator: F is two bytes.
Thirty-nine strings in six places
Sort the 39 addresses and they fall into six runs. Each run is one load command from section 3.2.
| Where | Addresses | Count | Examples |
|---|---|---|---|
| load command strings in the header | 0x100000404, 0x100000490 | 2 | /usr/lib/dyld, /usr/lib/libSystem.B.dylib |
__TEXT,__cstring, file 1904 | 0x100000770 to 0x1000007cf | 10 | F, D, C, B, A, usage: ledger <before> <after> [score...]\n, change %d%%\n, total %d\n, score %d grade %s\n, and one empty string |
LC_DYLD_CHAINED_FIXUPS import names, file 32768 | 0x100008069 to 0x1000080a7 | 6 | ___stack_chk_fail, _atoi, _printf |
LC_DYLD_EXPORTS_TRIE edge labels, file 32944 | 0x1000080b2 to 0x100008111 | 7 | _, _label, grade, main, percent_change, total |
LC_SYMTAB string table, file 33304 | 0x10000821a to 0x1000082a5 | 13 | __mh_execute_header, _grade_label, _labels |
LC_CODE_SIGNATURE identifier, file 33456 | 0x10000831c | 1 | ledger-arm64-O1 |
The ten in __cstring are the program's own text. The section is 95 bytes, and Ghidra's block for it in section 3.4 is 96. The block runs to the start of __const at 0x1000007d0. The extra byte at 0x1000007cf is the alignment pad, and Ghidra defined it as an empty string of length 1. That item is real and harmless, and you will see pads like it in every linked image.
The export trie is a prefix tree of the exported names. Its edges carry shared prefixes once. Ghidra's string data therefore holds seven fragments, _, _label, _mh_execute_header, grade, main, percent_change, and total, and not the six export names. The string table of LC_SYMTAB holds the thirteen full names, which match the nsyms of 13. The last string is the code signature's identifier, the output file name that the linker embedded. That is why the capture kit warns that a different output name gives different bytes.
Strings a function refers to
The dossier of _grade_label has a referenced_strings facet with one item, F at 0x100000770, from the load at 0x1000005c8. The function does not load F. It loads a pointer from _labels at 0x100004030, the 40-byte __const in __DATA_CONST that holds five pointers to the five labels. Ghidra followed the first pointer and recorded the string behind it, and its referenced_names facet lists both _labels and s_F_100000770 from the same instruction. Read a referenced string as a string the function can reach, not as the only one.
In the x86-64 object the same five labels sit in .rodata.str1.1, the ten-byte block in section 3.4, and string_count is 20. Lesson 32 reads the ELF string tables that hold the other ten.
What the inventory cannot prove
The limit is in the first word of the rule: defined. Three kinds of text are not Data. A compiler can pack a string into a struct. The analyzer can skip a string without a terminator. A program can build a string at run time. The list has none of them.
The capture target has none of those, so the 39 items are the whole file. For a target you did not build, treat an absent string as unknown. When you know an address, read_bytes returns the bytes and xrefs returns who uses them, as the limitation says. Section 5.2 shows how rea records that kind of unknown.
rea (rea-agents) with the Ghidra provider rea-agents 6.7.0, Ghidra 12.1.4 · 27dc42d · 2026-10-18 · Edition 2026.10