How to get c++ enum value in Xcode? - xcode

I would like to know if this is possible to get the value of c++ enum item in Xcode.
In Visual Studio you just have to hover the item and you got a tooltip with its value but it does not do the same in Xcode.
I also tried to print the value in lldb console without success.
For instance with this simple enum:
enum Params{
eP1,
eP2,
eP3,
eP4,
eP5,
};
I tried different ways like p eP1 or p Param::eP1.
I also tried with an enum class with the same result.

At present, you have to use enumName:enumElement, but that is working for me:
> cat foo.cpp
#include <stdio.h>
enum Params
{
eP1,
eP2,
eP3,
eP4
};
int main()
{
enum Params elem = eP1;
printf ("%d\n", elem);
return 0;
}
> lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) b s -p printf
Breakpoint 1: where = a.out`main + 29 at foo.cpp:14, address = 0x0000000100000f6d
(lldb) run
Process 26752 launched: '/private/tmp/a.out' (x86_64)
Process 26752 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f6d a.out`main at foo.cpp:14
11 int main()
12 {
13 enum Params elem = eP1;
-> 14 printf ("%d\n", elem);
^
15 return 0;
16 }
Target 0: (a.out) stopped.
(lldb) expr Params::eP1
(int) $0 = 0
If you still can't get this to work, can you post a more complete example where it fails?
The problem for lldb, BTW, is that the debug information is organized into the full debug information and then a name->info accelerator table. lldb depends on the accelerator tables for lookup (otherwise it would have to go looking through all the debug info which can get pretty slow for big apps). The accelerator tables at present only have the name of the enum, not the element names.

Related

cannot inspect "if let" variables in gdb

I'm having trouble inspecting variables set by if-let statements, for instance the following main.rs in a freshly created cargo project named "iflet-rust":
#[derive(Debug)]
struct Stuff;
fn maybe() -> Option<Stuff> {
Some(Stuff {})
}
fn main() {
if let Some(first) = maybe() {
println!("first {:?}", first); // line 8, cannot inspect 'first' here
}
let maybe_stuff = maybe();
if maybe_stuff.is_some() {
let second = maybe_stuff.unwrap();
println!("second {:?}", second); // no problem here
}
}
Then running cargo build and rust-gdb target/debug/iflet-rust
Reading symbols from target/debug/iflet-rust...
(gdb) b main.rs:8
Breakpoint 1 at 0x83f1: file src/main.rs, line 8.
(gdb) b main.rs:14
Breakpoint 2 at 0x848b: file src/main.rs, line 14.
(gdb) r
Starting program: iflet-rust/target/debug/iflet-rust
Breakpoint 1, iflet_rust::main () at src/main.rs:8
8 println!("first {:?}", first); // cannot inspect 'first' here
(gdb) p first
No symbol 'first' in current context
(gdb) info locals
No locals.
(gdb) c
Continuing.
first Stuff
Breakpoint 2, iflet_rust::main () at src/main.rs:14
14 println!("second {:?}", second); // no problem here
(gdb) info locals
second = iflet_rust::Stuff
maybe_stuff = core::option::Option::Some
Is this a know limitation or am I missing something?
It was an issue in the compiler, updating to Rust from 1.60 to 1.63 fixes the problem.
I shouldn't have limited my search to open issues, unfortunate timing.
See https://github.com/rust-lang/rust/issues/97799

Can I tell LLDB to remove the active breakpoint?

When LLDB triggers breakpoint X, is there a command that will disable or remove X and then continue?
That's an interesting idea. There's no built in command to do this in lldb but it would be easy to implement as a user-defined command written in Python. SBThread::GetStopReason() will be eStopReasonBreakpoint if that thread stopped because of a breakpoint. SBThread::GetStopReasonDataCount() will return 2 -- indicating that the breakpoint id and location id are available. SBThread::GetStopReasonDataAtIndex(0) will give you the breakpoint ID, SBThread::GetStopReasonDataAtIndex(1) will give you the location ID. (a single user-specified breakpoint may resolve to multiple locations. e.g. an inlined function, or a function name that occurs in multiple libraries in a single program.)
Here's a quick & dirty example of a python command that does this. I put this in ~/lldb where I save my lldb user-defined commands and then in my ~/.lldbinit file I have a line like command script import ~/lldb/disthis.py.
In use, it looks like this:
% lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) br s -n main
Breakpoint 1: where = a.out`main + 15 at a.c:4, address = 0x0000000100000f4f
(lldb) r
Process 67487 launched: '/private/tmp/a.out' (x86_64)
Process 67487 stopped
* thread #1: tid = 0x290c51, 0x0000000100000f4f a.out`main + 15 at a.c:4, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
#0: 0x0000000100000f4f a.out`main + 15 at a.c:4
1 #include <stdio.h>
2 int main()
3 {
-> 4 puts ("HI");
5 puts ("HI");
6 }
(lldb) com scr imp ~/lldb/disthis.py
(lldb) disthis
Breakpoint 1.1 disabled.
(lldb) br li
Current breakpoints:
1: name = 'main', locations = 1
1.1: where = a.out`main + 15 at a.c:4, address = 0x0000000100000f4f, unresolved, hit count = 1 Options: disabled
(lldb)
Pretty straightforward.
# import this into lldb with a command like
# command script import disthis.py
import lldb
def disthis(debugger, command, *args):
"""Usage: disthis
Disables the breakpoint the currently selected thread is stopped at."""
target = None
thread = None
if len(args) == 2:
# Old lldb invocation style
result = args[0]
if debugger and debugger.GetSelectedTarget() and debugger.GetSelectedTarget().GetProcess():
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
elif len(args) == 3:
# New (2015 & later) lldb invocation style where we're given the execution context
exe_ctx = args[0]
result = args[1]
target = exe_ctx.GetTarget()
thread = exe_ctx.GetThread()
else:
print "Unknown python function invocation from lldb."
return
if thread == None:
print >>result, "error: process is not paused, or has not been started yet."
result.SetStatus (lldb.eReturnStatusFailed)
return
if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
print >>result, "error: not stopped at a breakpoint."
result.SetStatus (lldb.eReturnStatusFailed)
return
if thread.GetStopReasonDataCount() != 2:
print >>result, "error: Unexpected number of StopReasonData returned, expected 2, got %d" % thread.GetStopReasonDataCount()
result.SetStatus (lldb.eReturnStatusFailed)
return
break_num = thread.GetStopReasonDataAtIndex(0)
location_num = thread.GetStopReasonDataAtIndex(1)
if break_num == 0 or location_num == 0:
print >>result, "error: Got invalid breakpoint number or location number"
result.SetStatus (lldb.eReturnStatusFailed)
return
bkpt = target.FindBreakpointByID (break_num)
if location_num > bkpt.GetNumLocations():
print >>result, "error: Invalid location number"
result.SetStatus (lldb.eReturnStatusFailed)
return
bkpt_loc = bkpt.GetLocationAtIndex(location_num - 1)
if bkpt_loc.IsValid() != True:
print >>result, "error: Got invalid BreakpointLocation"
result.SetStatus (lldb.eReturnStatusFailed)
return
bkpt_loc.SetEnabled(False)
print >>result, "Breakpoint %d.%d disabled." % (break_num, location_num)
return
def __lldb_init_module (debugger, dict):
debugger.HandleCommand('command script add -f %s.disthis disthis' % __name__)

Can a breakpoint display the contents of "const unsigned char* variable"?

I'm on the trail of why the contents of a TXT record in a Bonjour service discovery is sometimes being incompletely interpreted, and I've reached a point where it would be really useful to have a breakpoint print out the contents of an unsigned char in a callback (I've tried NSLog, but using NSLog in a threaded callback can get really tricky).
The callback function is defined this way:
static void resolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char* fullname, const char* hosttarget, uint16_t port, uint16_t txtLen,
const unsigned char* txtRecord, void* context) {
So I'm interested in the txtRecord
Right now my breakpoint is using:
memory read --size 4 --format x --count 4 `txtRecord`
But that's only because that was an example on the lldv.llvm.org example page ;-) It's certainly showing data that I expect to be there, partially.
Do I have to apply informed knowledge of the length or can the breakpoint be coded such that it uses the length that is present? I'm thinking that instead of "hard coding" the two 4s in the example there ought to be a way to wrap in other read instructions inside back ticks like I did with the variable name.
Looking at http://lldb.llvm.org/varFormats.html I thought I'd try a format of C instead of x but that prints out series of dots which must mean I picked a wrong format or something.
I just tried
memory read `txtRecord`
and that's almost exactly what I wanted to see as it gives:
0x1c5dd884: 10 65 6e 30 3d 31 39 32 2e 31 36 38 2e 31 2e 33 .en0=192.168.1.3
0x1c5dd894: 36 0a 70 6f 72 74 3d 35 30 32 37 38 00 00 00 00 6.port=50278....
This looks really close:
memory read `txtRecord` --format C
giving:
0x1d0c6974: .en0=192.168.1.36.port=50278....
If that's the best I can get, I guess I can deal with the length bytes in front of each of the two strings in that txtRecord.
I'm asking this question because I'd like to display the actual and correct values... the bug is that sometimes the IP address comes back wrong, losing the frontmost 1, other times the port comes back "short" (in network byte order) with non-numeric characters at the end, like "502¿" instead of "50278" (in this example run).
My initial response to this question, while informative, was not complete. I originally thought the problem being reported was just about printing a c-string array of type unsigned char * where the default formatters (char *) weren't being used. That answer comes first. Then comes the answer about how to print this (somewhat unique) array of pascal strings data that the program is actually dealing with.
First answer: lldb knows how to handle the char * well; it's the unsigned char * bit that is making it behave a little worse than usual. e.g. if txtRecord were a const char *,
(lldb) p txtRecord
(const char *) $0 = 0x0000000100000f51 ".en0=192.168.1.36.port=50278"
You can copy the type summary lldb has built in for char * for unsigned char *. type summary list lists all of the built in type summaries; copying lldb-179.5's summaries for char *:
(lldb) type summary add -p -C false -s ${var%s} 'unsigned char *'
(lldb) type summary add -p -C false -s ${var%s} 'const unsigned char *'
(lldb) fr va txtRecord
(const unsigned char *) txtRecord = 0x0000000100000f51 ".en0=192.168.1.36.port=50278"
(lldb) p txtRecord
(const unsigned char *) $2 = 0x0000000100000f51 ".en0=192.168.1.36.port=50278"
(lldb)
Of course you can put these in your ~/.lldbinit file and they'll be picked up by Xcode et al from now on.
Second answer: To print the array of pascal strings that this is actually using, you'll need to create a python function. It will take two arguments, the size of the pascal string buffer (txtLen) and the address of the start of the buffer (txtRecord). Create a python file like pstrarray.py (I like to put these in a directory I made, ~/lldb) and load it into your lldb via the ~/.lldbinit file so you have the command available:
command script import ~/lldb/pstrarray.py
The python script is a little long; I'm sure someone more familiar with python could express this more concisely. There's also a bunch of error handling which adds bulk. But the main idea is to take two parameters: the size of the buffer and the pointer to the buffer. The user will express these with variable names like pstrarray txtLen txtRecord, in which case you could look up the variables in the current frame, but they might also want to use an acutal expression like pstrarray sizeof(str) str. So we need to pass these parameters through the expression evaluation engine to get them down to an integer size and a pointer address. Then we read the memory out of the process and print the strings.
import lldb
import shlex
import optparse
def pstrarray(debugger, command, result, dict):
command_args = shlex.split(command)
parser = create_pstrarray_options()
try:
(options, args) = parser.parse_args(command_args)
except:
return
if debugger and debugger.GetSelectedTarget() and debugger.GetSelectedTarget().GetProcess():
process = debugger.GetSelectedTarget().GetProcess()
if len(args) < 2:
print "Usage: pstrarray size-of-buffer pointer-to-array-of-pascal-strings"
return
if process.GetSelectedThread() and process.GetSelectedThread().GetSelectedFrame():
frame = process.GetSelectedThread().GetSelectedFrame()
size_of_buffer_sbval = frame.EvaluateExpression (args[0])
if not size_of_buffer_sbval.IsValid() or size_of_buffer_sbval.GetValueAsUnsigned (lldb.LLDB_INVALID_ADDRESS) == lldb.LLDB_INVALID_ADDRESS:
print 'Could not evaluate "%s" down to an integral value' % args[0]
return
size_of_buffer = size_of_buffer_sbval.GetValueAsUnsigned ()
address_of_buffer_sbval = frame.EvaluateExpression (args[1])
if not address_of_buffer_sbval.IsValid():
print 'could not evaluate "%s" down to a pointer value' % args[1]
return
address_of_buffer = address_of_buffer_sbval.GetValueAsUnsigned (lldb.LLDB_INVALID_ADDRESS)
# If the expression eval didn't give us an integer value, try it again with an & prepended.
if address_of_buffer == lldb.LLDB_INVALID_ADDRESS:
address_of_buffer_sbval = frame.EvaluateExpression ('&%s' % args[1])
if address_of_buffer_sbval.IsValid():
address_of_buffer = address_of_buffer_sbval.GetValueAsUnsigned (lldb.LLDB_INVALID_ADDRESS)
if address_of_buffer == lldb.LLDB_INVALID_ADDRESS:
print 'could not evaluate "%s" down to a pointer value' % args[1]
return
err = lldb.SBError()
pascal_string_buffer = process.ReadMemory (address_of_buffer, size_of_buffer, err)
if (err.Fail()):
print 'Failed to read memory at address 0x%x' % address_of_buffer
return
pascal_string_array = bytearray(pascal_string_buffer, 'ascii')
index = 0
while index < size_of_buffer:
length = ord(pascal_string_buffer[index])
print "%s" % pascal_string_array[index+1:index+1+length]
index = index + length + 1
def create_pstrarray_options():
usage = "usage: %prog"
description='''print an buffer which has an array of pascal strings in it'''
parser = optparse.OptionParser(description=description, prog='pstrarray',usage=usage)
return parser
def __lldb_init_module (debugger, dict):
parser = create_pstrarray_options()
pstrarray.__doc__ = parser.format_help()
debugger.HandleCommand('command script add -f %s.pstrarray pstrarray' % __name__)
and an example program to run this on:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main ()
{
unsigned char str[] = {16,'e','n','0','=','1','9','2','.','1','6','8','.','1','.','3','6',
10,'p','o','r','t','=','5','1','6','8','7'};
uint8_t *p = str;
while (p < str + sizeof (str))
{
int len = *p++;
char buf[len + 1];
strlcpy (buf, (char*) p, len + 1);
puts (buf);
p += len;
}
puts ("done"); // break here
}
and in use:
(lldb) br s -p break
Breakpoint 1: where = a.out`main + 231 at a.c:17, address = 0x0000000100000ed7
(lldb) r
Process 74549 launched: '/private/tmp/a.out' (x86_64)
en0=192.168.1.36
port=51687
Process 74549 stopped
* thread #1: tid = 0x1c03, 0x0000000100000ed7 a.out`main + 231 at a.c:17, stop reason = breakpoint 1.1
#0: 0x0000000100000ed7 a.out`main + 231 at a.c:17
14 puts (buf);
15 p += len;
16 }
-> 17 puts ("done"); // break here
18 }
(lldb) pstrarray sizeof(str) str
en0=192.168.1.36
port=51687
(lldb)
While it's cool that it's possible to do this in lldb, it's not as smooth as we'd like to see. If the size of the buffer and the address of the buffer were contained in a single object, struct PStringArray {uint16_t size; uint8_t *addr;}, that would work much better. You could define a type summary formatter for all variables of type struct PStringArray and no special commands would be required. You'd still need to write a python function, but it could get all the information it needed out of the object directly so it would disappear into the lldb type format system. You could just write (lldb) p strs and the custom formatter function would be called on strs to print all the strings in there.

How can I find out what is changing an object (or a simple variable) in Xcode 4 / lldb?

In some debuggers this is called "setting a trap" on a variable. What I want to do is trigger a breakpoint on any statement that changes the object. Or changes a property of the object.
I have an NSMutableDictionary that gets a value/key added to it but I can't find any statement that could be doing that.
You can set a watchpoint (from here):
Set a watchpoint on a variable when it is written to.
(lldb) watchpoint set variable -w write global_var
(lldb) watch set var -w write global_var
(gdb) watch global_var
Set a watchpoint on a memory location when it is written into. The size of the region to watch for defaults to the pointer size if no '-x byte_size' is specified. This command takes raw input, evaluated as an expression returning an unsigned integer pointing to the start of the region, after the '--' option terminator.
(lldb) watchpoint set expression -w write -- my_ptr
(lldb) watch set exp -w write -- my_ptr
(gdb) watch -location g_char_ptr
Set a condition on a watchpoint.
(lldb) watch set var -w write global
(lldb) watchpoint modify -c '(global==5)'
(lldb) c
...
(lldb) bt
* thread #1: tid = 0x1c03, 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16, stop reason = watchpoint 1
frame #0: 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16
frame #1: 0x0000000100000eac a.out`main + 108 at main.cpp:25
frame #2: 0x00007fff8ac9c7e1 libdyld.dylib`start + 1
(lldb) frame var global
(int32_t) global = 5
List all watchpoints.
(lldb) watchpoint list
(lldb) watch l
(gdb) info break
Delete a watchpoint.
(lldb) watchpoint delete 1
(lldb) watch del 1
(gdb) delete 1
Watchpoints are used to track a write to an address in memory (the default behavior). If you know where an object is in memory (you have a pointer to it), and you know the offset into the object that you care about, that's what watchpoints are for. For instance, in a simple C example, if you have:
struct info
{
int a;
int b;
int c;
};
int main()
{
struct info variable = {5, 10, 20};
variable.a += 5; // put a breakpoint on this line, run to the breakpoint
variable.b += 5;
variable.c += 5;
return variable.a + variable.b + variable.c;
}
Once you're at a breakpoint on variable.a, do:
(lldb) wa se va variable.c
(lldb) continue
And the program will pause when variable.c has been modified. (I didn't bother to type out the full "watch set variable" command).
With a complex object like an NSMutableDictionary, for instance, I don't think watchpoints will do what you need. You would need to know the implementation details of the NSMutableDictionary object layout to know which word (or words) of memory to set a watchpoint.

View array in LLDB: equivalent of GDB's '#' operator in Xcode 4.1

I would like to view an array of elements pointed to by a pointer. In GDB this can be done by treating the pointed memory as an artificial array of a given length using the operator '#' as
*pointer # length
where length is the number of elements I want to view.
The above syntax does not work in LLDB supplied with Xcode 4.1.
Is there any way how to accomplish the above in LLDB?
There are two ways to do this in lldb.
Most commonly, you use the parray lldb command which takes a COUNT and an EXPRESSION; EXPRESSION is evaluated and should result in a pointer to memory. lldb will then print COUNT items of that type at that address. e.g.
parray 10 ptr
where ptr is of type int *.
Alternatively, it can be done by casting the pointer to a pointer-to-array.
For example, if you have a int* ptr, and you want to view it as an array of ten integers, you can do
p *(int(*)[10])ptr
Because it relies only on standard C features, this method works without any plugins or special settings. It likewise works with other debuggers like GDB or CDB, even though they also have specialized syntaxes for printing arrays.
Starting with the lldb in Xcode 8.0, there is a new built-in parray command. So you can say:
(lldb) parray <COUNT> <EXPRESSION>
to print the memory pointed to by the result of the EXPRESSION as an array of COUNT elements of the type pointed to by the expression.
If the count is stored in a variable available in the current frame, then remember you can do:
(lldb) parray `count_variable` pointer_to_malloced_array
That's a general lldb feature, any command-line argument in lldb surrounded in backticks gets evaluated as an expression that returns an integer, and then the integer gets substituted for the argument before command execution.
The only way I found was via a Python scripting module:
""" File: parray.py """
import lldb
import shlex
def parray(debugger, command, result, dict):
args = shlex.split(command)
va = lldb.frame.FindVariable(args[0])
for i in range(0, int(args[1])):
print va.GetChildAtIndex(i, 0, 1)
Define a command "parray" in lldb:
(lldb) command script import /path/to/parray.py
(lldb) command script add --function parray.parray parray
Now you can use "parray variable length":
(lldb) parray a 5
(double) *a = 0
(double) [1] = 0
(double) [2] = 1.14468
(double) [3] = 2.28936
(double) [4] = 3.43404
With Xcode 4.5.1 (which may or may not help you now), you can do this in the lldb console:
(lldb) type summary add -s "${var[0-63]}" "float *"
(lldb) frame variable pointer
(float *) pointer = 0x000000010ba92950 [0.0,1.0,2.0,3.0, ... ,63.0]
This example assumes that 'pointer' is an array of 64 floats: float pointer[64];
It doesn't seem to be supported yet.
You could use the memory read function (memory read / x), like
(lldb) memory read -ff -c10 `test`
to print a float ten times from that pointer. This should be the same functionality as gdb's #.
Starting with Martin R answer I improved it as follow:
If the pointer is not a simple variable, e.g.:
struct {
int* at;
size_t size;
} a;
Then "parray a.at 5" fails.
I fixed this by replacing "FindVariable" with "GetValueForVariablePath".
Now what if the elements in your array are aggregates, e.g.:
struct {
struct { float x; float y; }* at;
size_t size;
} a;
Then "parray a.at 5" prints: a.at->x, a.at->y, a.at[2], a.at[3], a.at[4] because GetChildAtIndex() returns members of aggregates.
I fixed this by resolving "a.at" + "[" + str(i) + "]" inside the loop instead of resolving "a.at" and then retrieving its children.
Added an optional "first" argument (Usage: parray [FIRST] COUNT), which is useful when you have a huge number of elements.
Made it do the "command script add -f parray.parray parray" at init
Here is my modified version:
import lldb
import shlex
def parray(debugger, command, result, dict):
args = shlex.split(command)
if len(args) == 2:
count = int(args[1])
indices = range(count)
elif len(args) == 3:
first = int(args[1]), count = int(args[2])
indices = range(first, first + count)
else:
print 'Usage: parray ARRAY [FIRST] COUNT'
return
for i in indices:
print lldb.frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add -f parray.parray parray')
I tried to add a comment but that wasn't great for posting a full answer so I made my own answer. This solves the problem with getting "No Value". You need to get the current frame as I believe lldb.frame is set at module import time so it doesn't have the current frame when you stop at a breakpoint if you load the module from .lldbinit. The other version would work if you import or reloaded the script when you stopped at the breakpoint. The version below should always work.
import lldb
import shlex
#lldb.command('parray', 'command script add -f parray.parray parray')
def parray(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
args = shlex.split(command)
if len(args) == 2:
count = int(args[1])
indices = range(count)
elif len(args) == 3:
first = int(args[1])
count = int(args[2])
indices = range(first, first + count)
else:
print 'Usage: parray ARRAY [FIRST] COUNT'
return
for i in indices:
print frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")
To inspect variables you can use the frame variable command (fr v is the shortest unique prefix) which has a -Z flag which does exactly what you want:
(lldb) fr v buffer -Z5
(int64_t *) buffer = 0x000000010950c000 {
(int64_t) [0] = 0
(int64_t) [1] = 0
(int64_t) [2] = 0
(int64_t) [3] = 0
(int64_t) [4] = 0
}
unfortunately expression does not support that flag
Well at that point, you may as well write your own custom C function and invoke it with:
call (int)myprint(args)

Resources