# User comments (analysis.comments)

analysis.comments: malcat.UserComments

  The `analysis.comments` object is a `malcat.UserComments` instance that gives you access to all the comments added by the user.

Comments are simple text strings added by the user at a given address. They can be viewed in the Hexadecimal view, Structure/text view or Disassembly view (if you have them activated in the Highlighting). They are saved within a `.malcat` project. In addition to the UI, comments can also be parsed and edited programmatically as we will see in this chapter.

Adding user comments via the UI

## Navigating over and editing comments

To list and search for user comments, you can use the methods from the `UserComments` class:

class malcat.UserComments

  This class contains all comments added by the user, either via the user interface or the python bindings. Note that all addresses used in this class are effective addresses. See Addressing in Malcat for more details.

  ### Navigation

  __iter__()

    Iterate over all the user comments

        for com in analysis.comments:
            print(f"{analysis.ppa(com.address)}: {com.text}")

    Return type:

      iterator over `UserComment`

  __getitem__(interval)

    Iterate over all the comments contained in the interval (effective address):

        coms = list(analysis.comments[analysis.p2a(0) : analysis.p2a(0x5000)])
        print("there are {} comments in range[#0-#5000[".format(len(coms)))

    Parameters:

      interval (slice) – effective address interval

    Return type:

      iterator over the list of comments (`UserComment`)

  __getitem__(ea)

    Returns the `UserComment` at the effective address ea.

        ep_rva = analysis.struct['OptionalHeader']['AddressOfEntryPoint']
        ep_comment = analysis.comments[analysis.r2a(ep_rva)]

    Parameters:

      ea (int) – effective address

    Return type:

      `UserComment`

    Raises:

      `KeyError` if no comment is defined at ea

  __contains__(ea)

    return True iff there exists a comment at effective address ea

    Parameters:

      ea (int) – address to query

    Return type:

      bool

  find(ea)

    return the `UserComment` at the effective address ea, or None if no one can be found.

    Parameters:

      ea (int) – effective address for the query

    Return type:

      `UserComment` or None

  find_forward(ea)

    return the `UserComment` which at the effective address ea or the one after ea, or None if no `UserComment` is defined beyond ea.

        first_comment = analysis.comments.find_forward(0)
        if first_comment is None:
            raise ValueError("No comment!")

    Parameters:

      ea (int) – effective address for the query

    Return type:

      `UserComment` or None

  find_backward(ea)

    return the `UserComment` which at the effective address ea or the first one before ea, or None if no `UserComment` is defined before ea.

        last_comment = analysis.comments.find_backward(analysis.map.end)
        if last_comment is None:
            raise ValueError("No comment!")

    Parameters:

      ea (int) – effective address for the query

    Return type:

      `UserComment` or None

  __len__()

    return the number of user comments

        if len(analysis.comments) == 0:
            raise ValueError("No comment found!")

    Return type:

      int

  ### Edit

  add(comment)

    add a new comment object to the analysis. Returns true on success. Will register the operation into the Undo/redo manager.

        address = analysis.v2a(0x401000)
        c = malcat.UserComment(address, "a comment text")
        if not analysis.comments.add(c):
            raise ValueError(f"Could not add comment {c} at {analysis.ppa(address)}")

    Parameters:

      comment (UserComment) – the comment to add

    Return type:

      bool

  __setitem__(ea, text)

    > add a new comment at the given effective address. Like `add()`, but with a simplified prototype. Will also register the operation into the Undo/redo manager.

    >     analysis.comments[analysis.v2a(0x401000)] = "a user comment"

    > param int ea:

    >   the address of the comment

    > param str text:

    >   the text of the comment

    remove(ea)

      remove an existing comment object from the analysis. Returns true on success. Will register the delete operation into the Undo/redo manager.

          if not analysis.comments.remove(analysis.v2a(0x401000)):
              raise ValueError(f"Could not remove comment at {analysis.ppa(address)}")

      Parameters:

        ea (int) – the address of the comment to delete

      Return type:

        bool

  __delitem__(ea)

    shortcut for `remove()`

        del analysis.comments[analysis.v2a(0x401000)]

    Parameters:

      ea (int) – the address of the comment to delete

## User comment object

A user comment is simply an arbitrary text string associated to a given address in Malcat.

class malcat.UserComment
  __init__(ea, text)

    > Create a new comment instance, for use with the `UserComments.add()` function

    >     address = analysis.v2a(0x401000)
    >     c = malcat.UserComment(address, "a comment text")
    >     if not analysis.comments.add(c):
    >         raise ValueError(f"Could not add comment {c} at {analysis.ppa(address)}")

    > param int ea:

    >   the address of the comment

    > param str text:

    >   the text of the comment

    address: int (effective address)

      the address of the comment

    text: str

      the content of the comment. May contains newlines.

    __repr__()

      return the value of the `text` property

      Return type:

        str

## Note about editing comments

### Undo/redo

Each comment you add gets saved in the list of undoable operations, which can be somewhat expensive if you plan to add thousands of comments. In general, if you plan to do a lot of modifications (comments or other types of edits like file writes for instance), you can chose to deactivate undos:

    analysis.history.record(False)
    # ... add your comments, they won't appear in the undo list
    for i in range(malcat.map.end):
         malcat.comments[i] = "..."
    # ... reactivate undo/redo
    analysis.history.record(True)

Note

Edits which are not recorded to the undo list are invisible to Malcat. It means Malcat will not see that the file has been modified and the UI won’t offer you to save your modifications on quit.

If you stil want to record your edits in the undo/redo but you would like to group them in just one operation, you can do it too:

    with analysis.history.group()
        # ... add your comments
        for i in range(malcat.map.end):
             malcat.comments[i] = "..."
     analysis.history.undo()     # <-- will undo all comments in one go