I have a C struct that looks something like this:
struct room {
void *reset_first;
}
I have a Golang struct that looks something like this:
type reset struct {
command string
}
Thanks to the joys of cgo, I can do the following from Go:
func someStuff(a *C.room, b *reset) {
a.reset_first = unsafe.Pointer(b)
}
and all is well
Then I attempt to retrieve it later:
func otherStuff(a *C.room) {
var r = (*reset)(a.reset_first)
fmt.Println(r.command)
}
and I end up with a segfault:
Thread 12 "test" received signal SIGSEGV, Segmentation fault.
316 fmt.Println(r.command)
but some of the values I get from inspection with gdb surprise me:
(gdb) info args
a = 0x7fffd5bc2d48
(gdb) info locals
r = 0x5
(gdb) print a
$1 = (struct main._Ctype_struct_room *) 0x7fffd5bc2d48
(gdb) print b
$2 = (struct main.reset *) 0x5
(gdb) print *a
3 = {_type = 2, _ = "\000\000\000", reset_first = 0xc422224a80}
How does r end up as 0x5 not 0xc422224a80?
I'm not surprised that trying to dereference 5 results in a segfault, but I'm baffled as to where the 5 came from!
Related
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
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.
I encode an Int64 (on the graphics card) with unsafeAddressOf of some instances (that are properly stored in and retained by some array).
I then would like to get back to my instances from my Int64. I manage to get an UnsafePointer<MyClass> correctly initialized from my Int64.
Then, I do:
let x = UnsafePointer<MyClass>.memory.
But using x crashes.
I understand it is unsafe and tricky considering ARC. But still, is there any way to achieve this in Swift, or is it helpless?
Thanks.
What you are trying to do is extremely unsafe, as you yourself said, and there are probably safer approaches to solving whatever problem you are working on, but here is a complete example that does it:
func getPointer<T:AnyObject>(obj : T) -> Int64
{
return unsafeBitCast(unsafeAddressOf(obj), Int64.self)
}
func recoverObject<T:AnyObject>(ptr : Int64) -> T
{
return Unmanaged<T>.fromOpaque(COpaquePointer(bitPattern: Int(ptr))).takeUnretainedValue()
}
class C {
var cID = 0
func foo() {
print("Instance of C, id = \(cID)")
}
}
class D {
var dID = 0
func foo() {
print("Instance of D, id = \(dID)")
}
}
let c : C = C()
let d : D = D()
c.cID = 123;
d.dID = 321;
let cPtr : Int64 = getPointer(c)
let dPtr : Int64 = getPointer(d)
c.cID *= 10
let c1 : C = recoverObject(cPtr)
let d1 : D = recoverObject(dPtr)
c1.foo()
d1.foo()
The output is:
Instance of C, id = 1230
Instance of D, id = 321
Thanks to user3441734 for some helpful hints! Note the use of generics. The functions for getting a "pointer" and de-referencing it should work with any class (won't work with structs, though).
As far as safer ways of doing this, the answer would depend on the context of what you are doing. Why can't the array of instances be accessed wherever you need the instances instead of obtaining them via Int64s? If the array is actually maintained by (Objective-)C code in a 3rd party library, then there are additional problems that may arise due to memory alignment etc. It may be possible to write C code that would return instances to Swift code in a safer way.
Please let me know about more details if the answer doesn't work for some reason.
class C {
func foo() {
print("C")
}
}
var c = C()
let addr = unsafeAddressOf(c)
dump(addr)
/*
▿ UnsafePointer(0x7F86E942B230)
- pointerValue: 140217415807536
*/
let pC = withUnsafePointer(&c) { (p) -> UnsafePointer<C> in
return p
}
dump(pC)
/*
▿ UnsafePointer(0x10DE5B390)
- pointerValue: 4528124816
*/
dump(pC.memory)
/*
- C #0
*/
let opaquePointer = COpaquePointer(addr)
let unmanagedC = Unmanaged<C>.fromOpaque(opaquePointer)
dump(unmanagedC)
/*
▿ Swift.Unmanaged<C>
- _value: C #0
*/
// I still dont have an idea how to use it ...
ha, i got it!
unmanagedC.takeUnretainedValue().foo() // prints C !
i'm working on porting this C API in go https://github.com/shammash/vde3, the library has is own event loop that use libevent, i'm using CGO.
the library require a full vde_event_handler that is composed this way
{event_add = 0x7fffe4de0db0, event_del = 0xc2000123a8, timeout_add = 0xc200000090, timeout_del = 0xc200010400}
a struct with a series of pointers to functions
during execution this field are set to NULL and i can't understand why, i think it may be the go garbage collector that (for some reason) find the reference dandling and remove them, but this shouldn't be the case
this is the incriminated function https://github.com/kurojishi/govde3/blob/master/govde.go#L23
func createNewEventHandler() *C.vde_event_handler {
var libevent_eh C.vde_event_handler
C.event_base_new()
return &libevent_eh
}
and here is a gdb log
(gdb) p *libevenet_eh
No symbol "libevenet_eh" in current context.
(gdb) p *libevent_eh
$1 = {event_add = 0x7fffe0000900, event_del = 0x30302e3028, timeout_add = 0x65736c6166, timeout_del = 0x0}
(gdb) info locals
libevent_eh = 0xc200000098
err = {__methods = 0x0, __object = 0x0}
(gdb) n
Breakpoint 1, govde.createNewEventHandler ()
at /home/kurojishi/golang/src/github.com/kurojishi/govde3/govde.go:23
23 func createNewEventHandler() C.vde_event_handler {
(gdb) info locals
$ret11 = {event_add = 0x7fffe4de0db0, event_del = 0xc2000123a8, timeout_add = 0xc200000090, timeout_del = 0xc200010400}
(gdb) n
Breakpoint 2, govde.createNewEventHandler ()
at /home/kurojishi/golang/src/github.com/kurojishi/govde3/govde.go:24
24 var libevent_eh C.vde_event_handler
(gdb) info locals
libevent_eh = {event_add = 0x0, event_del = 0x3, timeout_add = 0x7fffe4de0f8f, timeout_del = 0x7fffe4de0f8f}
$ret11 = {event_add = 0x0, event_del = 0x0, timeout_add = 0x0, timeout_del = 0x0}
You are allocating a new event handler in Go in createNewEventHandler, passing it to the C code in VdeContext.Init, and then dropping the pointer. The effect is that sometime after VdeContext.Init returns, the Go garbage collector will collect the event handler structure, even though the C code still has a pointer to it. The code will be left holding a pointer to memory that will change unpredictably.
When you allocate memory in Go and pass a pointer to C, you must keep the pointer alive in Go for as long as the C code needs to reference it.
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.