| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- #!/usr/bin/env python3
- """Initialization for lldb."""
- __copyright__ = """
- Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- Exceptions. See /LICENSE for license information.
- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- """
- # This script is only meant to be used from LLDB.
- import lldb # type: ignore
- import os
- import re
- from typing import Any
- project_root = os.path.dirname(os.path.realpath(__file__))
- ci = lldb.debugger.GetCommandInterpreter()
- result = lldb.SBCommandReturnObject()
- def RunCommand(cmd: str, print_command: bool = True) -> Any:
- """Runs a command and prints it to the console to show that it ran."""
- if print_command:
- print(f"(lldb) {cmd}")
- ci.HandleCommand(cmd, result)
- return result.GetOutput()
- RunCommand(f"settings append target.source-map . {project_root}")
- RunCommand(f"settings append target.source-map /proc/self/cwd {project_root}")
- # Matches the output of `print Dump(...)` and captures the stuff from inside the
- # std::string while discarding the std::string type.
- dump_re = re.compile(r'\(std::string\) "([\s\S]+)"', re.MULTILINE)
- # A helper to ease calling the Dump() free functions.
- def cmd_dump(debugger: Any, command: Any, result: Any, dict: Any) -> None:
- def print_usage() -> None:
- print(
- """
- Dumps the value of an associated ID, using the C++ Dump() functions.
- Usage:
- dump <CONTEXT> [<EXPR>|-- <EXPR>|<TYPE><ID>|<TYPE> <ID>]
- Args:
- CONTEXT is the dump context, such a SemIR::Context reference, a SemIR::File,
- a Parse::Context, or a Lex::TokenizeBuffer.
- EXPR is a C++ expression such as a variable name. Use `--` to prevent it from
- being treated as a TYPE and ID.
- TYPE can be `inst`, `constant`, `generic`, `impl`, `entity_name`, etc. See
- the `Label` string in `IdBase` classes to find possible TYPE names,
- though only Id types that have a matching `Make...Id()` function are
- supported.
- ID is an integer number, such as `42`, in hex, such as in `inst6000000A`. It
- can come with a `0x` prefix, allowing easier copy-paste from raw printed
- hex values (such as via the `p/x` lldb command).
- Example usage:
- # Dumps the `inst_id` local variable, with a `context` local variable.
- dump context inst_id
- # Dumps the instruction with id 42, with a `context()` method for accessing
- # the `Check::Context&`.
- dump context() inst42
- """
- )
- args = command.split(" ")
- if len(args) < 2:
- print_usage()
- return
- context = args[0]
- # The set of "Make" functions in dump.cpp.
- id_types = {
- "class": "SemIR::MakeClassId",
- "constant": "SemIR::MakeConstantId",
- "constraint": "SemIR::MakeNamedConstraintId",
- "symbolic_constant": "SemIR::MakeSymbolicConstantId",
- "entity_name": "SemIR::MakeEntityNameId",
- "facet_type": "SemIR::MakeFacetTypeId",
- "function": "SemIR::MakeFunctionId",
- "generic": "SemIR::MakeGenericId",
- "impl": "SemIR::MakeImplId",
- "inst_block": "SemIR::MakeInstBlockId",
- "inst": "SemIR::MakeInstId",
- "interface": "SemIR::MakeInterfaceId",
- "name": "SemIR::MakeNameId",
- "name_scope": "SemIR::MakeNameScopeId",
- "identified_facet_type": "SemIR::MakeIdentifiedFacetTypeId",
- "require_block": "SemIR::MakeRequireImplsBlockId",
- "require": "SemIR::MakeRequireImplsId",
- "specific": "SemIR::MakeSpecificId",
- "specific_interface": "SemIR::MakeSpecificInterfaceId",
- "struct_type_fields": "SemIR::MakeStructTypeFieldsId",
- "type": "SemIR::MakeTypeId",
- }
- def print_dump(context: str, expr: str) -> None:
- cmd = f"p Dump({context}, {expr})"
- out = RunCommand(cmd, print_command=False)
- if m := re.match(dump_re, out):
- # Use the `dump_re` match to print just the interesting part of the
- # dump output.
- print(m[1])
- else:
- # Unexpected output, show the command that was run.
- print(f"(lldb) {cmd}")
- print(out)
- # Try to find a type + id from the input args. If not, the id will be passed
- # through directly to C++, as it can be a variable name.
- found_id_type = False
- # Look for <type><id> as a single argument.
- if m := re.fullmatch("([a-z_]+)(?:0x)?([0-9A-Fa-f]+)", args[1]):
- if m[1] in id_types:
- if len(args) != 2:
- print_usage()
- return
- make_id_fn = id_types[m[1]]
- id = int(m[2], 16)
- print_dump(context, f"{make_id_fn}({id})")
- found_id_type = True
- # Look for <type> <id> as two arguments.
- if args[1] in id_types:
- if len(args) != 3:
- print_usage()
- return
- if m := re.fullmatch("(?:0x)?([0-9A-Fa-f]+)", args[2]):
- make_id_fn = id_types[args[1]]
- id = int(m[1], 16)
- print_dump(context, f"{make_id_fn}({id})")
- found_id_type = True
- if not found_id_type:
- # Use `--` to escape a variable name like `inst22`.
- if args[1] == "--":
- expr = " ".join(args[2:])
- else:
- expr = " ".join(args[1:])
- print_dump(context, expr)
- def __lldb_init_module(debugger: Any, internal_dict: Any) -> None:
- RunCommand("command script add -f lldbinit.cmd_dump dump")
|