Annotations

Annotations are a handy feature introduced in Radare2 5.9.6 that allows users to associate cross-project metadata with specific functions. Unlike comments or other metadata that are tied to a specific project or session, annotations are persistent and stored globally. This makes them particularly useful for tracking notes and observations across different projects without needing to worry about manually saving them.

The annotations are associated with the filename and function address, and it's stored in a dedicated cache directory, making them available even after you leave the session. You can think of annotations as a place to store function-specific notes, decompilation output, or other important information that you want to keep handy.

R2_CACHEDIR=~/.local/share/radare2/cache/
${R2_CACHEDIR}/ano.${filename}.{func_address}.txt

Using the ano

Annotations can be managed using the ano command. Below is an overview of the available options:

[0x00000000]> ano?
Usage: ano  [*] # function anotations
| ano                show or edit annotations for the current function
| ano-*              remove all annotations for current file
| ano-$$             remove annotations for current function
| ano*               dump all annotations in ano= commands
| ano=[base64:]text  set anotation text in base64 for current function
| anoe               edit annotation using cfg.editor
| anos               show current function annotation
| anol               display first line of function annotation if any
[0x00000000]>

Key Features

Persistent Across Sessions:

Annotations are stored globally in the XDG cache directory. This ensures that they are accessible across different sessions, even if no project is used.

Multiline Annotations:

Annotations can contain multiple lines of text, making them ideal for storing detailed notes, such as decompilation output, comments, or any other observations about a function.

Only the first line of the annotation will be displayed in the disassembly. Take this in mind when writing them to make them look nicer in the disassembly listing.

You can disable this feature by toggling the e asm.anos eval variable.

Cross-Project:

Since annotations are not tied to any specific project, they can be shared across different projects that analyze the same binary. This is useful when working with multiple teams or revisiting an old analysis.

Examples

Setting an Annotation for a Function

To add an annotation to the current function, you can simply use the ano= command with base64-encoded text:

[0x00000000]> ano=[b64text]

Editing and Viewing Annotations

If you want to manually edit the annotation for the current function, use the anoe command, which allows you to modify the annotation interactively:

[0x00000000]> anoe

You can also view the full annotation using anos:

[0x00000000]> anos

If you only want to see the first line of the annotation (which is useful for quick reference), you can use anol:

[0x00000000]> anol

Removing Annotations

To remove all annotations for the current file, you can use the ano-* command:

[0x00000000]> ano-*

Annotations In Action

Using Annotations to Cache Decompilation Output

Annotations can also be used to improve efficiency when working with decompiled code. For example, the decai -e cache=true setting in Radare2 enables the caching of decompiled output. This prevents Radare2 from having to re-decompile the same function multiple times, thus saving time during the analysis.

Here's an example of how this works:

  • Decompiling a function using AI requires consuming tokens or cpu time, which tends to be slow and expensive.
  • By enabling caching with decai -e cache=true, Decai will store the decompilation output in an annotation. The next time you view the same function, the cached annotation will be used instead of calling the decompiler again.

This is particularly helpful when working with large binaries or performing repetitive decompilation tasks.

$ r2pm -ci decai # install the decai decompiler
$ r2 -c 'decai -e cache=true' <binary>

By leveraging annotations in this way, you can significantly reduce the overhead of reprocessing functions during analysis.