15#include "llvm/ADT/StringRef.h"
44 bool process_is_valid =
46 if (!process_is_valid) {
47 result.
AppendError(
"There's no process or it is not alive.");
55static const char *
RSA[4] = {
"-",
"to",
"To",
"TO"};
61 for (i = 0; i < 4; ++i)
62 if (Arg.contains(
RSA[i]))
70 Target *target,
Args &args, std::vector<uint32_t> &wp_ids) {
73 if (target ==
nullptr)
77 wp_ids.push_back(watch_sp->GetID());
83 llvm::StringRef Minus(
"-");
84 std::vector<llvm::StringRef> StrRefArgs;
85 llvm::StringRef first;
86 llvm::StringRef second;
91 for (
auto &entry : args.
entries()) {
93 StrRefArgs.push_back(entry.ref());
97 std::tie(first, second) = entry.ref().split(
RSA[idx]);
99 StrRefArgs.push_back(first);
100 StrRefArgs.push_back(Minus);
102 StrRefArgs.push_back(second);
106 uint32_t beg, end,
id;
107 size_t size = StrRefArgs.size();
108 bool in_range =
false;
109 for (i = 0; i < size; ++i) {
110 llvm::StringRef Arg = StrRefArgs[i];
114 if (Arg.getAsInteger(0, end))
117 for (
id = beg;
id <= end; ++
id)
118 wp_ids.push_back(
id);
122 if (i < (size - 1) && StrRefArgs[i + 1] == Minus) {
123 if (Arg.getAsInteger(0, beg))
131 if (Arg.getAsInteger(0, beg))
133 wp_ids.push_back(beg);
143#pragma mark List::CommandOptions
144#define LLDB_OPTIONS_watchpoint_list
145#include "CommandOptions.inc"
153 interpreter,
"watchpoint list",
154 "List all watchpoints at configurable levels of detail.", nullptr,
155 eCommandRequiresTarget) {
161 m_arguments.push_back(arg);
177 const int short_option = m_getopt_table[option_idx].val;
179 switch (short_option) {
190 llvm_unreachable(
"Unimplemented option");
201 return llvm::ArrayRef(g_watchpoint_list_options);
211 Target *target = &GetSelectedTarget();
214 std::optional<uint32_t> num_supported_hardware_watchpoints =
217 if (num_supported_hardware_watchpoints)
219 "Number of supported hardware watchpoints: %u\n",
220 *num_supported_hardware_watchpoints);
225 std::unique_lock<std::recursive_mutex> lock;
228 size_t num_watchpoints = watchpoints.
GetSize();
230 if (num_watchpoints == 0) {
241 for (
size_t i = 0; i < num_watchpoints; ++i) {
248 std::vector<uint32_t> wp_ids;
250 target, command, wp_ids)) {
251 result.
AppendError(
"Invalid watchpoints specification.");
255 const size_t size = wp_ids.size();
256 for (
size_t i = 0; i < size; ++i) {
278 "Enable the specified disabled watchpoint(s). If "
279 "no watchpoints are specified, enable all of them.",
280 nullptr, eCommandRequiresTarget) {
286 m_arguments.push_back(arg);
301 Target *target = &GetSelectedTarget();
305 std::unique_lock<std::recursive_mutex> lock;
310 size_t num_watchpoints = watchpoints.
GetSize();
312 if (num_watchpoints == 0) {
313 result.
AppendError(
"No watchpoints exist to be enabled.");
322 (uint64_t)num_watchpoints);
326 std::vector<uint32_t> wp_ids;
328 target, command, wp_ids)) {
329 result.
AppendError(
"Invalid watchpoints specification.");
334 const size_t size = wp_ids.size();
335 for (
size_t i = 0; i < size; ++i)
353 "Disable the specified watchpoint(s) without "
354 "removing it/them. If no watchpoints are "
355 "specified, disable them all.",
356 nullptr, eCommandRequiresTarget) {
362 m_arguments.push_back(arg);
377 Target *target = &GetSelectedTarget();
381 std::unique_lock<std::recursive_mutex> lock;
385 size_t num_watchpoints = watchpoints.
GetSize();
387 if (num_watchpoints == 0) {
388 result.
AppendError(
"No watchpoints exist to be disabled.");
397 (uint64_t)num_watchpoints);
400 result.
AppendError(
"Disable all watchpoints failed\n");
404 std::vector<uint32_t> wp_ids;
406 target, command, wp_ids)) {
407 result.
AppendError(
"Invalid watchpoints specification.");
412 const size_t size = wp_ids.size();
413 for (
size_t i = 0; i < size; ++i)
425#define LLDB_OPTIONS_watchpoint_delete
426#include "CommandOptions.inc"
435 "Delete the specified watchpoint(s). If no "
436 "watchpoints are specified, delete them all.",
437 nullptr, eCommandRequiresTarget) {
443 m_arguments.push_back(arg);
466 const int short_option = m_getopt_table[option_idx].val;
468 switch (short_option) {
473 llvm_unreachable(
"Unimplemented option");
484 return llvm::ArrayRef(g_watchpoint_delete_options);
488 bool m_force =
false;
493 Target *target = &GetSelectedTarget();
497 std::unique_lock<std::recursive_mutex> lock;
502 size_t num_watchpoints = watchpoints.
GetSize();
504 if (num_watchpoints == 0) {
505 result.
AppendError(
"No watchpoints exist to be deleted.");
509 if (command.
empty()) {
510 if (!m_options.m_force &&
511 !m_interpreter.Confirm(
512 "About to delete all watchpoints, do you want to do that?",
519 (uint64_t)num_watchpoints);
526 std::vector<uint32_t> wp_ids;
529 result.
AppendError(
"Invalid watchpoints specification.");
534 const size_t size = wp_ids.size();
535 for (
size_t i = 0; i < size; ++i)
550#pragma mark Ignore::CommandOptions
551#define LLDB_OPTIONS_watchpoint_ignore
552#include "CommandOptions.inc"
558 "Set ignore count on the specified watchpoint(s). "
559 "If no watchpoints are specified, set them all.",
560 nullptr, eCommandRequiresTarget) {
566 m_arguments.push_back(arg);
590 const int short_option = m_getopt_table[option_idx].val;
592 switch (short_option) {
594 if (option_arg.getAsInteger(0, m_ignore_count))
595 error.SetErrorStringWithFormat(
"invalid ignore count '%s'",
596 option_arg.str().c_str());
599 llvm_unreachable(
"Unimplemented option");
610 return llvm::ArrayRef(g_watchpoint_ignore_options);
615 uint32_t m_ignore_count = 0;
620 Target *target = &GetSelectedTarget();
624 std::unique_lock<std::recursive_mutex> lock;
629 size_t num_watchpoints = watchpoints.
GetSize();
631 if (num_watchpoints == 0) {
632 result.
AppendError(
"No watchpoints exist to be ignored.");
640 (uint64_t)num_watchpoints);
644 std::vector<uint32_t> wp_ids;
646 target, command, wp_ids)) {
647 result.
AppendError(
"Invalid watchpoints specification.");
652 const size_t size = wp_ids.size();
653 for (
size_t i = 0; i < size; ++i)
669#pragma mark Modify::CommandOptions
670#define LLDB_OPTIONS_watchpoint_modify
671#include "CommandOptions.inc"
679 interpreter,
"watchpoint modify",
680 "Modify the options on a watchpoint or set of watchpoints in the "
682 "If no watchpoint is specified, act on the last created "
684 "Passing an empty argument clears the modification.",
685 nullptr, eCommandRequiresTarget) {
691 m_arguments.push_back(arg);
715 const int short_option = m_getopt_table[option_idx].val;
717 switch (short_option) {
719 m_condition = std::string(option_arg);
720 m_condition_passed =
true;
723 llvm_unreachable(
"Unimplemented option");
731 m_condition_passed =
false;
735 return llvm::ArrayRef(g_watchpoint_modify_options);
741 bool m_condition_passed =
false;
746 Target *target = &GetSelectedTarget();
750 std::unique_lock<std::recursive_mutex> lock;
755 size_t num_watchpoints = watchpoints.
GetSize();
757 if (num_watchpoints == 0) {
758 result.
AppendError(
"No watchpoints exist to be modified.");
764 watch_sp->SetCondition(m_options.m_condition.c_str());
768 std::vector<uint32_t> wp_ids;
770 target, command, wp_ids)) {
771 result.
AppendError(
"Invalid watchpoints specification.");
776 const size_t size = wp_ids.size();
777 for (
size_t i = 0; i < size; ++i) {
780 watch_sp->SetCondition(m_options.m_condition.c_str());
796#pragma mark SetVariable
802 interpreter,
"watchpoint set variable",
803 "Set a watchpoint on a variable. "
804 "Use the '-w' option to specify the type of watchpoint and "
805 "the '-s' option to specify the byte size to watch for. "
806 "If no '-w' option is specified, it defaults to modify. "
807 "If no '-s' option is specified, it defaults to the variable's "
809 "Note that there are limited hardware resources for watchpoints. "
810 "If watchpoint setting fails, consider disable/delete existing "
812 "to free up resources.",
814 eCommandRequiresFrame | eCommandTryTargetAPILock |
815 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
820(lldb) watchpoint set variable -w read_write my_global_var
823 " Watches my_global_var for read/write access, with the region to watch \
824corresponding to the byte size of the data type.");
834 arg.push_back(var_name_arg);
837 m_arguments.push_back(arg);
841 m_option_group.Finalize();
856 Options *GetOptions()
override {
return &m_option_group; }
859 static size_t GetVariableCallback(
void *baton,
const char *name,
861 size_t old_size = variable_list.
GetSize();
866 return variable_list.
GetSize() - old_size;
870 Target *target = GetDebugger().GetSelectedTarget().get();
877 "specify your program variable to watch for");
882 if (!m_option_watchpoint.watch_type_specified) {
897 result.
AppendError(
"specify exactly one variable to watch for");
903 uint32_t expr_path_options =
918 m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
919 variable_list, valobj_list));
929 addr = valobj_sp->GetAddressOf(
false, &addr_type);
933 size = m_option_watchpoint.watch_size == 0
935 : m_option_watchpoint.watch_size;
937 compiler_type = valobj_sp->GetCompilerType();
939 const char *error_cstr =
error.AsCString(
nullptr);
944 "expression path that matches '%s'",
950 uint32_t watch_type = 0;
951 switch (m_option_watchpoint.watch_type) {
973 "Watchpoint creation failed (addr=0x%" PRIx64
", size=%" PRIu64
974 ", variable expression='%s').\n",
976 if (
const char *error_message =
error.AsCString(
nullptr))
982 watch_sp->SetWatchVariable(
true);
984 if (var_sp->GetDeclaration().GetFile()) {
987 var_sp->GetDeclaration().DumpStopContext(&ss,
true);
988 watch_sp->SetDeclInfo(std::string(ss.
GetString()));
991 watch_sp->SetupVariableWatchpointDisabler(m_exe_ctx.GetFrameSP());
993 output_stream.
Printf(
"Watchpoint created: ");
1013 interpreter,
"watchpoint set expression",
1014 "Set a watchpoint on an address by supplying an expression. "
1015 "Use the '-l' option to specify the language of the expression. "
1016 "Use the '-w' option to specify the type of watchpoint and "
1017 "the '-s' option to specify the byte size to watch for. "
1018 "If no '-w' option is specified, it defaults to modify. "
1019 "If no '-s' option is specified, it defaults to the target's "
1020 "pointer byte size. "
1021 "Note that there are limited hardware resources for watchpoints. "
1022 "If watchpoint setting fails, consider disable/delete existing "
1024 "to free up resources.",
1026 eCommandRequiresFrame | eCommandTryTargetAPILock |
1027 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
1032(lldb) watchpoint set expression -w modify -s 1 -- foo + 32
1034 Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
1044 arg.push_back(expression_arg);
1047 m_arguments.push_back(arg);
1052 m_option_group.Finalize();
1059 bool WantsCompletion()
override {
return true; }
1061 Options *GetOptions()
override {
return &m_option_group; }
1064 bool DoExecute(llvm::StringRef raw_command,
1066 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
1070 Target *target = GetDebugger().GetSelectedTarget().get();
1075 llvm::StringRef expr = args.GetRawPart();
1078 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
1084 if (raw_command.trim().empty()) {
1085 result.
AppendError(
"required argument missing; specify an expression "
1086 "to evaluate into the address to watch for");
1091 if (!m_option_watchpoint.watch_type_specified) {
1110 options.
SetLanguage(m_option_watchpoint.language_type);
1115 result.
AppendError(
"expression evaluation of address to watch failed");
1117 if (valobj_sp && !valobj_sp->GetError().Success())
1118 result.
AppendError(valobj_sp->GetError().AsCString());
1123 bool success =
false;
1124 addr = valobj_sp->GetValueAsUnsigned(0, &success);
1126 result.
AppendError(
"expression did not evaluate to an address");
1130 if (m_option_watchpoint.watch_size != 0)
1131 size = m_option_watchpoint.watch_size;
1136 uint32_t watch_type;
1137 switch (m_option_watchpoint.watch_type) {
1157 CompilerType compiler_type(valobj_sp->GetCompilerType());
1163 watch_sp->SetWatchSpec(std::string(expr));
1165 output_stream.
Printf(
"Watchpoint created: ");
1167 output_stream.
EOL();
1171 ", size=%" PRIu64
").\n",
1172 addr, (uint64_t)size);
1173 if (
error.AsCString(
nullptr))
1192 interpreter,
"watchpoint set",
"Commands for setting a watchpoint.",
1193 "watchpoint set <subcommand> [<subcommand-options>]") {
1207#pragma mark MultiwordWatchpoint
1212 "Commands for operating on watchpoints.",
1213 "watchpoint <subcommand> [<command-options>]") {
1231 list_command_object->SetCommandName(
"watchpoint list");
1232 enable_command_object->SetCommandName(
"watchpoint enable");
1233 disable_command_object->SetCommandName(
"watchpoint disable");
1234 delete_command_object->SetCommandName(
"watchpoint delete");
1235 ignore_command_object->SetCommandName(
"watchpoint ignore");
1236 command_command_object->SetCommandName(
"watchpoint command");
1237 modify_command_object->SetCommandName(
"watchpoint modify");
1238 set_command_object->SetCommandName(
"watchpoint set");
static bool CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
static void AddWatchpointDescription(Stream &s, Watchpoint &wp, lldb::DescriptionLevel level)
static int32_t WithRSAIndex(llvm::StringRef Arg)
static const char * RSA[4]
static llvm::raw_ostream & error(Stream &strm)
~CommandOptions() override=default
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void OptionParsingStarting(ExecutionContext *execution_context) override
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectWatchpointDelete(CommandInterpreter &interpreter)
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
Options * GetOptions() override
~CommandObjectWatchpointDelete() override=default
~CommandObjectWatchpointDisable() override=default
bool DoExecute(Args &command, CommandReturnObject &result) override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
CommandObjectWatchpointDisable(CommandInterpreter &interpreter)
CommandObjectWatchpointEnable(CommandInterpreter &interpreter)
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
bool DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectWatchpointEnable() override=default
~CommandOptions() override=default
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
CommandObjectWatchpointIgnore(CommandInterpreter &interpreter)
bool DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectWatchpointIgnore() override=default
Options * GetOptions() override
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
~CommandOptions() override=default
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
CommandObjectWatchpointList(CommandInterpreter &interpreter)
~CommandObjectWatchpointList() override=default
Options * GetOptions() override
bool DoExecute(Args &command, CommandReturnObject &result) override
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
~CommandOptions() override=default
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
Options * GetOptions() override
~CommandObjectWatchpointModify() override=default
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectWatchpointModify(CommandInterpreter &interpreter)
CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter)
CommandObjectWatchpointSetVariable(CommandInterpreter &interpreter)
~CommandObjectWatchpointSet() override=default
CommandObjectWatchpointSet(CommandInterpreter &interpreter)
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
A command line argument class.
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
llvm::ArrayRef< ArgEntry > entries() const
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
~CommandObjectMultiwordWatchpoint() override
CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter)
static bool VerifyWatchpointIDs(Target *target, Args &args, std::vector< uint32_t > &wp_ids)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
std::vector< CommandArgumentData > CommandArgumentEntry
static void AddIDsArgumentData(CommandArgumentEntry &arg, lldb::CommandArgumentType ID, lldb::CommandArgumentType IDRange)
void AppendMessage(llvm::StringRef in_string)
void void AppendError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void AppendMessageWithFormat(const char *format,...) __attribute__((format(printf
Stream & GetOutputStream()
Generic representation of a type in a programming language.
std::optional< uint64_t > GetByteSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bytes.
"lldb/Utility/ArgCompletionRequest.h"
size_t GetCursorIndex() const
A uniqued constant string class.
void SetLanguage(lldb::LanguageType language)
void SetUnwindOnError(bool unwind=false)
void SetKeepInMemory(bool keep=true)
void SetCoerceToId(bool coerce=true)
void SetTryAllThreads(bool try_others=true)
void SetTimeout(const Timeout< std::micro > &timeout)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
void FindGlobalVariables(ConstString name, size_t max_matches, VariableList &variable_list) const
Find global and static variables by name.
A pair of an option list with a 'raw' string as a suffix.
A command line option parsing protocol class.
void NotifyOptionParsingStarting(ExecutionContext *execution_context)
This base class provides an interface to stack frames.
@ eExpressionPathOptionCheckPtrVsMember
@ eExpressionPathOptionsAllowDirectIVarAccess
lldb::ValueObjectSP GetValueForVariableExpressionPath(llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, uint32_t options, lldb::VariableSP &var_sp, Status &error)
Create a ValueObject for a variable name / pathname, possibly including simple dereference/child sele...
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t EOL()
Output and End of Line character to the stream.
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
void IndentMore(unsigned amount=2)
Increment the current indentation level.
lldb::WatchpointSP CreateWatchpoint(lldb::addr_t addr, size_t size, const CompilerType *type, uint32_t kind, Status &error)
bool IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count)
bool EnableWatchpointByID(lldb::watch_id_t watch_id)
const lldb::ProcessSP & GetProcessSP() const
bool RemoveAllWatchpoints(bool end_to_end=true)
bool RemoveWatchpointByID(lldb::watch_id_t watch_id)
bool DisableAllWatchpoints(bool end_to_end=true)
const ModuleList & GetImages() const
Get accessor for the images for this process.
const ArchSpec & GetArchitecture() const
WatchpointList & GetWatchpointList()
bool IgnoreAllWatchpoints(uint32_t ignore_count)
bool DisableWatchpointByID(lldb::watch_id_t watch_id)
lldb::WatchpointSP GetLastCreatedWatchpoint()
bool EnableAllWatchpoints(bool end_to_end=true)
lldb::ExpressionResults EvaluateExpression(llvm::StringRef expression, ExecutionContextScope *exe_scope, lldb::ValueObjectSP &result_valobj_sp, const EvaluateExpressionOptions &options=EvaluateExpressionOptions(), std::string *fixed_expression=nullptr, ValueObject *ctx_obj=nullptr)
A collection of ValueObject values that.
lldb::ValueObjectSP GetValueObjectAtIndex(size_t idx)
static Status GetValuesForVariableExpressionPath(llvm::StringRef variable_expr_path, ExecutionContextScope *scope, GetVariableCallback callback, void *baton, VariableList &variable_list, ValueObjectList &valobj_list)
This class is used by Watchpoint to manage a list of watchpoints,.
lldb::WatchpointSP GetByIndex(uint32_t i)
Returns a shared pointer to the watchpoint with index i.
lldb::WatchpointSP FindByID(lldb::watch_id_t watchID) const
Returns a shared pointer to the watchpoint with id watchID, const version.
void GetListMutex(std::unique_lock< std::recursive_mutex > &lock)
Sets the passed in Locker to hold the Watchpoint List mutex.
size_t GetSize() const
Returns the number of elements in this watchpoint list.
void GetDescription(Stream *s, lldb::DescriptionLevel level)
#define LLDB_WATCH_TYPE_WRITE
#define LLDB_WATCH_TYPE_MODIFY
#define LLDB_WATCH_TYPE_READ
A class that represents a running process on the host machine.
std::vector< OptionArgElement > OptionElementVector
@ eAddressTypeLoad
Address is an address as in the current target inferior process.
@ eVariablePathCompletion
@ eWatchpointIDCompletion
DescriptionLevel
Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls.
@ eDescriptionLevelVerbose
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
@ eLanguageTypeUnknown
Unknown or invalid language value.
ExpressionResults
The results of expression evaluation.
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeWatchpointIDRange
std::shared_ptr< lldb_private::Watchpoint > WatchpointSP
std::shared_ptr< lldb_private::Variable > VariableSP
@ eValueTypeVariableLocal
function local variables
Used to build individual command argument lists.
ArgumentRepetitionType arg_repetition
lldb::CommandArgumentType arg_type