Star wildcard ranges (e.g., "info thread 2.*")
Add support for specifying "all threads of inferior N", by writing "*" as thread number/range in thread ID lists. E.g., "info threads 2.*" or "thread apply 2.* bt". gdb/ChangeLog: 2016-01-15 Pedro Alves <palves@redhat.com> * NEWS: Mention star wildcard ranges. * cli/cli-utils.c (get_number_or_range): Check state->in_range first. (number_range_setup_range): New function. * cli/cli-utils.h (number_range_setup_range): New declaration. * thread.c (thread_apply_command): Support star TID ranges. * tid-parse.c (tid_range_parser_finished) (tid_range_parser_string, tid_range_parser_skip) (get_tid_or_range, get_tid_or_range): Handle TID_RANGE_STATE_STAR_RANGE. (tid_range_parser_star_range): New function. * tid-parse.h (enum tid_range_state) <TID_RANGE_STATE_STAR_RANGE>: New value. (tid_range_parser_star_range): New declaration. gdb/doc/ChangeLog: 2016-01-15 Pedro Alves <palves@redhat.com> * gdb.texinfo (Threads) <thread ID lists>: Document star ranges. gdb/testsuite/ChangeLog: 2016-01-15 Pedro Alves <palves@redhat.com> * gdb.multi/tids.exp: Test star wildcard ranges.
This commit is contained in:
parent
3f5b759880
commit
71ef29a86b
11 changed files with 185 additions and 30 deletions
|
@ -1,3 +1,19 @@
|
||||||
|
2016-01-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
* NEWS: Mention star wildcard ranges.
|
||||||
|
* cli/cli-utils.c (get_number_or_range): Check state->in_range first.
|
||||||
|
(number_range_setup_range): New function.
|
||||||
|
* cli/cli-utils.h (number_range_setup_range): New declaration.
|
||||||
|
* thread.c (thread_apply_command): Support star TID ranges.
|
||||||
|
* tid-parse.c (tid_range_parser_finished)
|
||||||
|
(tid_range_parser_string, tid_range_parser_skip)
|
||||||
|
(get_tid_or_range, get_tid_or_range): Handle
|
||||||
|
TID_RANGE_STATE_STAR_RANGE.
|
||||||
|
(tid_range_parser_star_range): New function.
|
||||||
|
* tid-parse.h (enum tid_range_state) <TID_RANGE_STATE_STAR_RANGE>:
|
||||||
|
New value.
|
||||||
|
(tid_range_parser_star_range): New declaration.
|
||||||
|
|
||||||
2016-01-15 Pedro Alves <palves@redhat.com>
|
2016-01-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
* thread.c (thread_apply_command): Use the tid range parser to
|
* thread.c (thread_apply_command): Use the tid range parser to
|
||||||
|
|
6
gdb/NEWS
6
gdb/NEWS
|
@ -34,6 +34,12 @@
|
||||||
[Switching to thread 2.1 (Thread 0x7ffff7fc2740 (LWP 8157))] (running)
|
[Switching to thread 2.1 (Thread 0x7ffff7fc2740 (LWP 8157))] (running)
|
||||||
(gdb)
|
(gdb)
|
||||||
|
|
||||||
|
* In commands that accept a list of thread IDs, you can now refer to
|
||||||
|
all threads of an inferior using a star wildcard. GDB accepts
|
||||||
|
"INF_NUM.*", to refer to all threads of inferior INF_NUM, and "*" to
|
||||||
|
refer to all threads of the current inferior. For example, "info
|
||||||
|
threads 2.*".
|
||||||
|
|
||||||
* You can use "info threads -gid" to display the global thread ID of
|
* You can use "info threads -gid" to display the global thread ID of
|
||||||
all threads.
|
all threads.
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,21 @@ init_number_or_range (struct get_number_or_range_state *state,
|
||||||
int
|
int
|
||||||
get_number_or_range (struct get_number_or_range_state *state)
|
get_number_or_range (struct get_number_or_range_state *state)
|
||||||
{
|
{
|
||||||
if (*state->string != '-')
|
if (state->in_range)
|
||||||
|
{
|
||||||
|
/* All number-parsing has already been done. Return the next
|
||||||
|
integer value (one greater than the saved previous value).
|
||||||
|
Do not advance the token pointer until the end of range is
|
||||||
|
reached. */
|
||||||
|
|
||||||
|
if (++state->last_retval == state->end_value)
|
||||||
|
{
|
||||||
|
/* End of range reached; advance token pointer. */
|
||||||
|
state->string = state->end_ptr;
|
||||||
|
state->in_range = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*state->string != '-')
|
||||||
{
|
{
|
||||||
/* Default case: state->string is pointing either to a solo
|
/* Default case: state->string is pointing either to a solo
|
||||||
number, or to the first number of a range. */
|
number, or to the first number of a range. */
|
||||||
|
@ -165,27 +179,26 @@ get_number_or_range (struct get_number_or_range_state *state)
|
||||||
state->in_range = 1;
|
state->in_range = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (! state->in_range)
|
|
||||||
error (_("negative value"));
|
|
||||||
else
|
else
|
||||||
{
|
error (_("negative value"));
|
||||||
/* state->string points to the '-' that betokens a range. All
|
|
||||||
number-parsing has already been done. Return the next
|
|
||||||
integer value (one greater than the saved previous value).
|
|
||||||
Do not advance the token pointer until the end of range
|
|
||||||
is reached. */
|
|
||||||
|
|
||||||
if (++state->last_retval == state->end_value)
|
|
||||||
{
|
|
||||||
/* End of range reached; advance token pointer. */
|
|
||||||
state->string = state->end_ptr;
|
|
||||||
state->in_range = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state->finished = *state->string == '\0';
|
state->finished = *state->string == '\0';
|
||||||
return state->last_retval;
|
return state->last_retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See documentation in cli-utils.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
number_range_setup_range (struct get_number_or_range_state *state,
|
||||||
|
int start_value, int end_value, const char *end_ptr)
|
||||||
|
{
|
||||||
|
gdb_assert (start_value > 0);
|
||||||
|
|
||||||
|
state->in_range = 1;
|
||||||
|
state->end_ptr = end_ptr;
|
||||||
|
state->last_retval = start_value - 1;
|
||||||
|
state->end_value = end_value;
|
||||||
|
}
|
||||||
|
|
||||||
/* Accept a number and a string-form list of numbers such as is
|
/* Accept a number and a string-form list of numbers such as is
|
||||||
accepted by get_number_or_range. Return TRUE if the number is
|
accepted by get_number_or_range. Return TRUE if the number is
|
||||||
in the list.
|
in the list.
|
||||||
|
|
|
@ -90,6 +90,14 @@ extern void init_number_or_range (struct get_number_or_range_state *state,
|
||||||
|
|
||||||
extern int get_number_or_range (struct get_number_or_range_state *state);
|
extern int get_number_or_range (struct get_number_or_range_state *state);
|
||||||
|
|
||||||
|
/* Setups STATE such that get_number_or_range returns numbers in range
|
||||||
|
START_VALUE to END_VALUE. When get_number_or_range returns
|
||||||
|
END_VALUE, the STATE string is advanced to END_PTR. */
|
||||||
|
|
||||||
|
extern void number_range_setup_range (struct get_number_or_range_state *state,
|
||||||
|
int start_value, int end_value,
|
||||||
|
const char *end_ptr);
|
||||||
|
|
||||||
/* Accept a number and a string-form list of numbers such as is
|
/* Accept a number and a string-form list of numbers such as is
|
||||||
accepted by get_number_or_range. Return TRUE if the number is
|
accepted by get_number_or_range. Return TRUE if the number is
|
||||||
in the list.
|
in the list.
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2016-01-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Threads) <thread ID lists>: Document star ranges.
|
||||||
|
|
||||||
2016-01-13 Pedro Alves <palves@redhat.com>
|
2016-01-13 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
* gdb.texinfo (Threads): Document the $_gthread convenience
|
* gdb.texinfo (Threads): Document the $_gthread convenience
|
||||||
|
|
|
@ -2912,16 +2912,35 @@ of inferior 1, the initial inferior.
|
||||||
@anchor{thread ID lists}
|
@anchor{thread ID lists}
|
||||||
@cindex thread ID lists
|
@cindex thread ID lists
|
||||||
Some commands accept a space-separated @dfn{thread ID list} as
|
Some commands accept a space-separated @dfn{thread ID list} as
|
||||||
argument. A list element can be a thread ID as shown in the first
|
argument. A list element can be:
|
||||||
field of the @samp{info threads} display, with or without an inferior
|
|
||||||
qualifier (e.g., @samp{2.1} or @samp{1}); or can be a range of thread
|
@enumerate
|
||||||
numbers, again with or without an inferior qualifier, as in
|
@item
|
||||||
@var{inf1}.@var{thr1}-@var{thr2} or @var{thr1}-@var{thr2} (e.g.,
|
A thread ID as shown in the first field of the @samp{info threads}
|
||||||
@samp{1.2-4} or @samp{2-4}). For example, if the current inferior is
|
display, with or without an inferior qualifier. E.g., @samp{2.1} or
|
||||||
1, the thread list @samp{1 2-3 4.5 6.7-9} includes threads 1 to 3 of
|
@samp{1}.
|
||||||
inferior 1, thread 5 of inferior 4 and threads 7 to 9 of inferior 6.
|
|
||||||
That is, in expanded qualified form, the same as @samp{1.1 1.2 1.3 4.5
|
@item
|
||||||
6.7 6.8 6.9}.
|
A range of thread numbers, again with or without an inferior
|
||||||
|
qualifier, as in @var{inf}.@var{thr1}-@var{thr2} or
|
||||||
|
@var{thr1}-@var{thr2}. E.g., @samp{1.2-4} or @samp{2-4}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
All threads of an inferior, specified with a star wildcard, with or
|
||||||
|
without an inferior qualifier, as in @var{inf}.@code{*} (e.g.,
|
||||||
|
@samp{1.*}) or @code{*}. The former refers to all threads of the
|
||||||
|
given inferior, and the latter form without an inferior qualifier
|
||||||
|
refers to all threads of the current inferior.
|
||||||
|
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
For example, if the current inferior is 1, and inferior 7 has one
|
||||||
|
thread with ID 7.1, the thread list @samp{1 2-3 4.5 6.7-9 7.*}
|
||||||
|
includes threads 1 to 3 of inferior 1, thread 5 of inferior 4, threads
|
||||||
|
7 to 9 of inferior 6 and all threads of inferior 7. That is, in
|
||||||
|
expanded qualified form, the same as @samp{1.1 1.2 1.3 4.5 6.7 6.8 6.9
|
||||||
|
7.1}.
|
||||||
|
|
||||||
|
|
||||||
@anchor{global thread numbers}
|
@anchor{global thread numbers}
|
||||||
@cindex global thread number
|
@cindex global thread number
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2016-01-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
* gdb.multi/tids.exp: Test star wildcard ranges.
|
||||||
|
|
||||||
2016-01-15 Pedro Alves <palves@redhat.com>
|
2016-01-15 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
* gdb.multi/tids.exp (thr_apply_info_thr_error): Remove "p 1234"
|
* gdb.multi/tids.exp (thr_apply_info_thr_error): Remove "p 1234"
|
||||||
|
|
|
@ -277,6 +277,36 @@ with_test_prefix "two inferiors" {
|
||||||
"warning: Unknown thread 30.1" \
|
"warning: Unknown thread 30.1" \
|
||||||
"thread apply \$inf.1"
|
"thread apply \$inf.1"
|
||||||
|
|
||||||
|
# Star ranges.
|
||||||
|
|
||||||
|
thr_apply_info_thr "1.*" \
|
||||||
|
"1.1 1.2 1.3"
|
||||||
|
|
||||||
|
thr_apply_info_thr "*" \
|
||||||
|
"1.1 1.2 1.3"
|
||||||
|
|
||||||
|
thr_apply_info_thr "1.* 2.1" \
|
||||||
|
"1.1 1.2 1.3 2.1"
|
||||||
|
|
||||||
|
thr_apply_info_thr "2.1 1.*" \
|
||||||
|
"1.1 1.2 1.3 2.1" \
|
||||||
|
"2.1 1.1 1.2 1.3"
|
||||||
|
|
||||||
|
thr_apply_info_thr "1.* 2.*" \
|
||||||
|
"1.1 1.2 1.3 2.1 2.2 2.3"
|
||||||
|
|
||||||
|
thr_apply_info_thr "2.* 1.*" \
|
||||||
|
"1.1 1.2 1.3 2.1 2.2 2.3" \
|
||||||
|
"2.1 2.2 2.3 1.1 1.2 1.3"
|
||||||
|
|
||||||
|
# There's no inferior 3, but "info threads" treats the thread list
|
||||||
|
# as a filter, so it's OK. "thread apply" complains about the
|
||||||
|
# unknown inferior through.
|
||||||
|
info_threads "1.1 3.*" \
|
||||||
|
"1.1"
|
||||||
|
gdb_test "thread apply 1.1 3.* p 1" \
|
||||||
|
"Thread 1.1.*warning: Unknown inferior 3"
|
||||||
|
|
||||||
# Now test a set of invalid thread IDs/ranges.
|
# Now test a set of invalid thread IDs/ranges.
|
||||||
|
|
||||||
thr_apply_info_thr_invalid "1." \
|
thr_apply_info_thr_invalid "1." \
|
||||||
|
@ -318,6 +348,11 @@ with_test_prefix "two inferiors" {
|
||||||
thr_apply_info_thr_error "${prefix}-\$one" "negative value"
|
thr_apply_info_thr_error "${prefix}-\$one" "negative value"
|
||||||
thr_apply_info_thr_error "${prefix}\$minus_one" \
|
thr_apply_info_thr_error "${prefix}\$minus_one" \
|
||||||
"negative value: ${prefix_re}\\\$minus_one"
|
"negative value: ${prefix_re}\\\$minus_one"
|
||||||
|
|
||||||
|
thr_apply_info_thr_error "${prefix}1-*" "inverted range"
|
||||||
|
thr_apply_info_thr_invalid "${prefix}*1"
|
||||||
|
thr_apply_info_thr_invalid "${prefix}*foo"
|
||||||
|
thr_apply_info_thr_invalid "${prefix}foo*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check that a valid thread ID list with a missing command errors
|
# Check that a valid thread ID list with a missing command errors
|
||||||
|
@ -330,6 +365,7 @@ with_test_prefix "two inferiors" {
|
||||||
gdb_test "thread apply 1-2" $output
|
gdb_test "thread apply 1-2" $output
|
||||||
gdb_test "thread apply 1.1-2" $output
|
gdb_test "thread apply 1.1-2" $output
|
||||||
gdb_test "thread apply $thr" $output
|
gdb_test "thread apply $thr" $output
|
||||||
|
gdb_test "thread apply 1.*" $output
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check that we do parse the inferior number and don't confuse it.
|
# Check that we do parse the inferior number and don't confuse it.
|
||||||
|
|
20
gdb/thread.c
20
gdb/thread.c
|
@ -1864,6 +1864,26 @@ thread_apply_command (char *tidlist, int from_tty)
|
||||||
inf = find_inferior_id (inf_num);
|
inf = find_inferior_id (inf_num);
|
||||||
if (inf != NULL)
|
if (inf != NULL)
|
||||||
tp = find_thread_id (inf, thr_num);
|
tp = find_thread_id (inf, thr_num);
|
||||||
|
|
||||||
|
if (tid_range_parser_star_range (&parser))
|
||||||
|
{
|
||||||
|
if (inf == NULL)
|
||||||
|
{
|
||||||
|
warning (_("Unknown inferior %d"), inf_num);
|
||||||
|
tid_range_parser_skip (&parser);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No use looking for threads past the highest thread number
|
||||||
|
the inferior ever had. */
|
||||||
|
if (thr_num >= inf->highest_thread_num)
|
||||||
|
tid_range_parser_skip (&parser);
|
||||||
|
|
||||||
|
/* Be quiet about unknown threads numbers. */
|
||||||
|
if (tp == NULL)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
{
|
{
|
||||||
if (show_inferior_qualified_tids ()
|
if (show_inferior_qualified_tids ()
|
||||||
|
|
|
@ -134,6 +134,7 @@ tid_range_parser_finished (struct tid_range_parser *parser)
|
||||||
case TID_RANGE_STATE_INFERIOR:
|
case TID_RANGE_STATE_INFERIOR:
|
||||||
return *parser->string == '\0';
|
return *parser->string == '\0';
|
||||||
case TID_RANGE_STATE_THREAD_RANGE:
|
case TID_RANGE_STATE_THREAD_RANGE:
|
||||||
|
case TID_RANGE_STATE_STAR_RANGE:
|
||||||
return parser->range_parser.finished;
|
return parser->range_parser.finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +151,7 @@ tid_range_parser_string (struct tid_range_parser *parser)
|
||||||
case TID_RANGE_STATE_INFERIOR:
|
case TID_RANGE_STATE_INFERIOR:
|
||||||
return parser->string;
|
return parser->string;
|
||||||
case TID_RANGE_STATE_THREAD_RANGE:
|
case TID_RANGE_STATE_THREAD_RANGE:
|
||||||
|
case TID_RANGE_STATE_STAR_RANGE:
|
||||||
return parser->range_parser.string;
|
return parser->range_parser.string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +163,8 @@ tid_range_parser_string (struct tid_range_parser *parser)
|
||||||
void
|
void
|
||||||
tid_range_parser_skip (struct tid_range_parser *parser)
|
tid_range_parser_skip (struct tid_range_parser *parser)
|
||||||
{
|
{
|
||||||
gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE)
|
gdb_assert ((parser->state == TID_RANGE_STATE_THREAD_RANGE
|
||||||
|
|| parser->state == TID_RANGE_STATE_STAR_RANGE)
|
||||||
&& parser->range_parser.in_range);
|
&& parser->range_parser.in_range);
|
||||||
|
|
||||||
tid_range_parser_init (parser, parser->range_parser.end_ptr,
|
tid_range_parser_init (parser, parser->range_parser.end_ptr,
|
||||||
|
@ -219,7 +222,16 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
|
||||||
}
|
}
|
||||||
|
|
||||||
init_number_or_range (&parser->range_parser, p);
|
init_number_or_range (&parser->range_parser, p);
|
||||||
parser->state = TID_RANGE_STATE_THREAD_RANGE;
|
if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
|
||||||
|
{
|
||||||
|
/* Setup the number range parser to return numbers in the
|
||||||
|
whole [1,INT_MAX] range. */
|
||||||
|
number_range_setup_range (&parser->range_parser, 1, INT_MAX,
|
||||||
|
skip_spaces_const (p + 1));
|
||||||
|
parser->state = TID_RANGE_STATE_STAR_RANGE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
parser->state = TID_RANGE_STATE_THREAD_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*inf_num = parser->inf_num;
|
*inf_num = parser->inf_num;
|
||||||
|
@ -247,7 +259,9 @@ get_tid_or_range (struct tid_range_parser *parser, int *inf_num,
|
||||||
|
|
||||||
/* If we're midway through a range, and the caller wants the end
|
/* If we're midway through a range, and the caller wants the end
|
||||||
value, return it and skip to the end of the range. */
|
value, return it and skip to the end of the range. */
|
||||||
if (thr_end != NULL && parser->state == TID_RANGE_STATE_THREAD_RANGE)
|
if (thr_end != NULL
|
||||||
|
&& (parser->state == TID_RANGE_STATE_THREAD_RANGE
|
||||||
|
|| parser->state == TID_RANGE_STATE_STAR_RANGE))
|
||||||
{
|
{
|
||||||
*thr_end = parser->range_parser.end_value;
|
*thr_end = parser->range_parser.end_value;
|
||||||
tid_range_parser_skip (parser);
|
tid_range_parser_skip (parser);
|
||||||
|
@ -280,6 +294,14 @@ tid_range_parser_get_tid (struct tid_range_parser *parser,
|
||||||
|
|
||||||
/* See tid-parse.h. */
|
/* See tid-parse.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
tid_range_parser_star_range (struct tid_range_parser *parser)
|
||||||
|
{
|
||||||
|
return parser->state == TID_RANGE_STATE_STAR_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See gdbthread.h. */
|
||||||
|
|
||||||
int
|
int
|
||||||
tid_is_in_list (const char *list, int default_inferior,
|
tid_is_in_list (const char *list, int default_inferior,
|
||||||
int inf_num, int thr_num)
|
int inf_num, int thr_num)
|
||||||
|
|
|
@ -44,6 +44,9 @@ enum tid_range_state
|
||||||
|
|
||||||
/* Parsing the thread number or thread number range. */
|
/* Parsing the thread number or thread number range. */
|
||||||
TID_RANGE_STATE_THREAD_RANGE,
|
TID_RANGE_STATE_THREAD_RANGE,
|
||||||
|
|
||||||
|
/* Parsing a star wildcard thread range. E.g., "1.*". */
|
||||||
|
TID_RANGE_STATE_STAR_RANGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* An object of this type is passed to tid_range_parser_get_tid. It
|
/* An object of this type is passed to tid_range_parser_get_tid. It
|
||||||
|
@ -142,6 +145,10 @@ extern int tid_range_parser_get_tid_range (struct tid_range_parser *parser,
|
||||||
int *inf_num,
|
int *inf_num,
|
||||||
int *thr_start, int *thr_end);
|
int *thr_start, int *thr_end);
|
||||||
|
|
||||||
|
/* Returns non-zero if processing a star wildcard (e.g., "1.*")
|
||||||
|
range. */
|
||||||
|
extern int tid_range_parser_star_range (struct tid_range_parser *parser);
|
||||||
|
|
||||||
/* Returns non-zero if parsing has completed. */
|
/* Returns non-zero if parsing has completed. */
|
||||||
extern int tid_range_parser_finished (struct tid_range_parser *parser);
|
extern int tid_range_parser_finished (struct tid_range_parser *parser);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue