How to invoke swift function from lldb using address (pointer)? - objective-c

I'm playing with lldb and I'm trying to call my swift static function. I was able to find its details in image, however I have no idea how to call it and pass arguments.
My output:
(lldb) image lookup -vs $S5project19ViewControllerUtilsC07setRootbC010storyboard13withAnimationySo12UIStoryboardC_SbtFZ
1 symbols match '$S5project19ViewControllerUtilsC07setRootbC010storyboard13withAnimationySo12UIStoryboardC_SbtFZ' in /Users/user/Library/Developer/CoreSimulator/Devices/DC7A5199-424E-4E38-A8A8-CB99C7D8CF82/data/Containers/Bundle/Application/BE7BB249-DB64-4228-B64E-EB430BCCE29E/project.app/project:
Address: project[0x00000002000fc970] (project.__TEXT.__text + 1027840)
Summary: project`static project.ViewControllerUtils.setRootViewController(storyboard: __C.UIStoryboard, withAnimation: Swift.Bool) -> () at ViewControllerUtils.swift:7
Module: file = "/Users/user/Library/Developer/CoreSimulator/Devices/DC7A5199-424E-4E38-A8A8-CB99C7D8CF82/data/Containers/Bundle/Application/BE7BB249-DB64-4228-B64E-EB430BCCE29E/project.app/project", arch = "x86_64"
CompileUnit: id = {0x00000000}, file = "/Users/user/mobile/company/iOS/project/project/Utils/ViewControllerUtils.swift", language = "swift"
Function: id = {0x7700000075}, name = "static project.ViewControllerUtils.setRootViewController(storyboard: __C.UIStoryboard, withAnimation: Swift.Bool) -> ()", mangled = "$S5project19ViewControllerUtilsC07setRootbC010storyboard13withAnimationySo12UIStoryboardC_SbtFZ", range = [0x000000010bd0c780-0x000000010bd0c82e)
FuncType: id = {0x7700000075}, byte-size = 8, decl = ViewControllerUtils.swift:7, compiler_type = "(UIKit.UIStoryboard, Swift.Bool) -> ()
"
Blocks: id = {0x7700000075}, range = [0x10bd0c780-0x10bd0c82e)
LineEntry: [0x000000010bd0c780-0x000000010bd0c79d): /Users/user/mobile/company/iOS/project/project/Utils/ViewControllerUtils.swift:7
Symbol: id = {0x00002a71}, range = [0x000000010ac0c780-0x000000010ac0c830), name="static project.ViewControllerUtils.setRootViewController(storyboard: __C.UIStoryboard, withAnimation: Swift.Bool) -> ()", mangled="$S5project19ViewControllerUtilsC07setRootbC010storyboard13withAnimationySo12UIStoryboardC_SbtFZ"
Variable: id = {0x6600000092}, name = "storyboard", type = "UIKit.UIStoryboard", location = DW_OP_fbreg(-16), decl = ViewControllerUtils.swift:7
Variable: id = {0x66000000a0}, name = "withAnimation", type = "Swift.Bool", location = DW_OP_fbreg(-24), decl = ViewControllerUtils.swift:7
Variable: id = {0x66000000ae}, name = "self", type = "#thick project.ViewControllerUtils.Type", location = DW_OP_fbreg(-32), decl = ViewControllerUtils.swift:7
Source code:
final class ViewControllerUtils {
static func setRootViewController(storyboard: UIStoryboard, withAnimation: Bool) {
setRootViewController(window: UIApplication.shared.keyWindow, storyboard: storyboard, withAnimation: withAnimation)
}
}
I know I could switch to Swift and invoke something like this:
expression -l swift -O -- ViewControllerUtils.setRootViewController(storyboard: UIKit.UIStoryboard(name: "Main", bundle: nil), withAnimation: true)
But I would like to learn how to invoke a function using its address or symbol without referencing to specific class like above.

I have found the solution.
Take address from range: Symbol: id = {0x00002a71}, range = [0x000000010ac0c780-0x000000010ac0c830) this one: 0x000000010ac0c780.
Import UIKit (lldb) po import UIKit
Create Storyboard:
(lldb) p UIStoryboard(name: "Main", bundle: nil)
(UIStoryboard) $R2 = 0x00006000006c8200 {
ObjectiveC.NSObject = {
isa = UIStoryboard
}
}
Cast raw address to function and invoke it using created Storyboard variable $R2:
(lldb) po unsafeBitCast(0x000000010ac0c780, to: (#convention(c)(UIKit.UIStoryboard, Bool) -> ()).self)($R2, true)
Here you can read also an interesting example of importing C function: Swift: How to call a C function loaded from a dylib

Related

How do I properly return as JSON-ified version of Parse object?

I'm hitting a custom function on my server, getting a PFObject in my Convos objects and returning that object from JS, which results in this string in my Objective-C code:
"<convos: 0x6080002ae220, objectId: e1VYAIFCyQ, localId: (null)> {
\n buyerDeleted = NO;\n buyerId = NNfjWZrk8r;\n buyerPicture = \"<PFFile: 0x60800065de80>\";\n buyerSentMessage = YES;\n buyerSentTwoMessages = YES;\n buyerUnseen = 0;\n buyerUser = \"<PFUser: 0x6080002f1900, objectId: NNfjWZrk8r, localId: (null)>\";\n buyerUsername = corby;\n convoId = bQLQWNEtwmNNfjWZrk8r;\n lastSent = \"<messages: 0x60c0000b8600, objectId: iYVIjJ6A3q, localId: (null)>\";\n lastSentDate = \"2018-06-05 19:09:52 +0000\";\n profileConvo = YES;\n sellerDeleted = NO;\n sellerId = bQLQWNEtwm;\n sellerSentMessage = YES;\n sellerUnseen = 0;\n sellerUser = \"<PFUser: 0x6080002f1a80, objectId: bQLQWNEtwm, localId: (null)>\";\n sellerUsername = tough;\n source = profile;\n totalMessages = 3;\n
}"
I'm trying to take the convo object in my JS and run convo.toJSON() on it (which seems like the solution) and then return it but that seems to take an extremely long time.
Any tips on how to return that Parse object so that I can ultimately turn it into an NSDictionary and then a PFObject in the client?
I think we got you covered in slack, but for anyone else who finds this:
Don't use toJSON() from your server, just return the Parse.Object
In your Obj-C code, add this line to the success block of your call back:
PFObject *resultParseObject = (PFObject*)object, where object is the _Nullable id object parameter to the callback of your cloud function.

How to read file comment field

In OS X Finder there is 'Comment' file property. It can be checked in finder by adding 'Comment' column or edited/checked after right clicking on file or folder and selecting 'Get info'.
How to read this value in swift or objective-c?
I checked already NSURL and none of them seems to be the right ones
Do not use the low-level extended attributes API to read Spotlight metadata. There's a proper Spotlight API for that. (It's called the File Metadata API.) Not only is it a pain in the neck, there's no guarantee that Apple will keep using the same extended attribute to store this information.
Use MDItemCreateWithURL() to create an MDItem for the file. Use MDItemCopyAttribute() with kMDItemFinderComment to obtain the Finder comment for the item.
Putting the pieces together (Ken Thomases reading answer above and writing answer link) you can extend URL with a computed property with a getter and a setter to read/write comments to your files:
update: Xcode 8.2.1 • Swift 3.0.2
extension URL {
var finderComment: String? {
get {
guard isFileURL else { return nil }
return MDItemCopyAttribute(MDItemCreateWithURL(kCFAllocatorDefault, self as CFURL), kMDItemFinderComment) as? String
}
set {
guard isFileURL, let newValue = newValue else { return }
let script = "tell application \"Finder\"\n" +
String(format: "set filePath to \"%#\" as posix file \n", absoluteString) +
String(format: "set comment of (filePath as alias) to \"%#\" \n", newValue) +
"end tell"
guard let appleScript = NSAppleScript(source: script) else { return }
var error: NSDictionary?
appleScript.executeAndReturnError(&error)
if let error = error {
print(error[NSAppleScript.errorAppName] as! String)
print(error[NSAppleScript.errorBriefMessage] as! String)
print(error[NSAppleScript.errorMessage] as! String)
print(error[NSAppleScript.errorNumber] as! NSNumber)
print(error[NSAppleScript.errorRange] as! NSRange)
}
}
}
}
As explained in the various answers to Mac OS X : add a custom meta data field to any file,
Finder comments can be read and set programmatically with getxattr() and setxattr(). They are stored as extended attribute
"com.apple.metadata:kMDItemFinderComment", and the value is a property
list.
This works even for files not indexed by Spotlight, such as those on a network server volume.
From the Objective-C code here
and here I made this simple Swift function
to read the Finder comment (now updated for Swift 4 and later):
func finderComment(url : URL) -> String? {
let XAFinderComment = "com.apple.metadata:kMDItemFinderComment"
let data = url.withUnsafeFileSystemRepresentation { fileSystemPath -> Data? in
// Determine attribute size:
let length = getxattr(fileSystemPath, XAFinderComment, nil, 0, 0, 0)
guard length >= 0 else { return nil }
// Create buffer with required size:
var data = Data(count: length)
// Retrieve attribute:
let result = data.withUnsafeMutableBytes { [count = data.count] in
getxattr(fileSystemPath, XAFinderComment, $0.baseAddress, count, 0, 0)
}
guard result >= 0 else { return nil }
return data
}
// Deserialize to String:
guard let data = data, let comment = try? PropertyListSerialization.propertyList(from: data,
options: [], format: nil) as? String else {
return nil
}
return comment
}
Example usage:
let url = URL(fileURLWithPath: "/path/to/file")
if let comment = finderComment(url: url) {
print(comment)
}
The function returns an optional string which is nil if the file
has no Finder comment, or if anything went wrong while retrieving it.

How to execute external program from Swift?

I am new in Swift and I did not found anything about executing external programs or access external processes using Swing language.
Is it possible to do in the current stage of the language development or I should use Objective-C instead?
Maybe there are some Objective-C libraries that can be used inside my Swift program?
Thanks.
You can run external programs using NSTask. For example, from Circle and Square:
import Foundation
func executeCommand(command: String, args: [String]) -> String {
let task = NSTask()
task.launchPath = command
task.arguments = args
let pipe = NSPipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: NSUTF8StringEncoding)
return output
}
let commandOutput = executeCommand("/bin/echo", ["Hello, I am here!"])
println("Command output: \(commandOutput)")
Improved version of Rob's answer (in that you don't need to specify the full path of your executable), and also updated for Swift 3:
import Foundation
func execCommand(command: String, args: [String]) -> String {
if !command.hasPrefix("/") {
let commandFull = execCommand(command: "/usr/bin/which", args: [command]).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return execCommand(command: commandFull, args: args)
} else {
let proc = Process()
proc.launchPath = command
proc.arguments = args
let pipe = Pipe()
proc.standardOutput = pipe
proc.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
return String(data: data, encoding: String.Encoding.utf8)!
}
}

Swift: How to get Console User, UID, and GID via SCDynamicStoreCopyConsoleUser?

I am able to get the Username, UID and GID from SCDynamicStoreCopyConsoleUser using python:
#!/usr/bin/python
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
cfuser = SCDynamicStoreCopyConsoleUser( None, None, None )
print cfuser[0] # Returns console user, e.g.: myUsername
print cfuser[1] # Returns console user’s UID, e.g.: 501
print cfuser[2] # Returns console user’s GID, e.g.: 20
How can I get this same return using Swift?
Swift Declaration of SCDynamicStoreCopyConsoleUser
func SCDynamicStoreCopyConsoleUser(_ store: SCDynamicStore!,
_ uid: CMutablePointer<uid_t>,
_ gid: CMutablePointer<gid_t>) -> Unmanaged<CFString>!
My Swift Call
var uid: CMutablePointer<uid_t>!
var gid: CMutablePointer<gid_t>!
var cfuser: NSArray = [SCDynamicStoreCopyConsoleUser(nil,uid,gid)]
// the return has only one element containing the username
The Swift function SCDynamicStoreCopyConsoleUser takes a CMutablePointer<uid_t> argument which means that you have to pass the address of a uid_t variable.
Also you should check if the call succeeded (otherwise nil is returned),
and you
have to convert the returned unmanaged object as described in
Working with Cocoa Data Types:
import SystemConfiguration
var uid: uid_t = 0
var gid: gid_t = 0
if let theResult = SCDynamicStoreCopyConsoleUser(nil, &uid, &gid) {
let name = theResult.takeUnretainedValue()
println("name = \(name), uid = \(uid), gid = \(gid)")
} else {
println("failed")
}

eclipse JDT setting the project

I am a beginner to Eclipse JDT. I was going through some tutorial and found one good example for creating the java file. In this below example in which project they will create the package and java file. I could not see any code pointing to any of the project name. Please make me understand if I am wrong. I just run the below example. I could not see any output..
AST ast = AST.newAST(AST.JLS3);
CompilationUnit unit = ast.newCompilationUnit();
PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
packageDeclaration.setName(ast.newSimpleName("example"));
unit.setPackage(packageDeclaration);
ImportDeclaration importDeclaration = ast.newImportDeclaration();
QualifiedName name =
ast.newQualifiedName(
ast.newSimpleName("java"),
ast.newSimpleName("util"));
importDeclaration.setName(name);
importDeclaration.setOnDemand(true);
unit.imports().add(importDeclaration);
TypeDeclaration type = ast.newTypeDeclaration();
type.setInterface(false);
type.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
type.setName(ast.newSimpleName("HelloWorld"));
MethodDeclaration methodDeclaration = ast.newMethodDeclaration();
methodDeclaration.setConstructor(false);
List modifiers = methodDeclaration.modifiers();
modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
modifiers.add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
methodDeclaration.setName(ast.newSimpleName("main"));
methodDeclaration.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID));
SingleVariableDeclaration variableDeclaration = ast.newSingleVariableDeclaration();
variableDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName("String"))));
variableDeclaration.setName(ast.newSimpleName("args"));
methodDeclaration.parameters().add(variableDeclaration);
org.eclipse.jdt.core.dom.Block block = ast.newBlock();
MethodInvocation methodInvocation = ast.newMethodInvocation();
name =
ast.newQualifiedName(
ast.newSimpleName("System"),
ast.newSimpleName("out"));
methodInvocation.setExpression(name);
methodInvocation.setName(ast.newSimpleName("println"));
InfixExpression infixExpression = ast.newInfixExpression();
infixExpression.setOperator(InfixExpression.Operator.PLUS);
StringLiteral literal = ast.newStringLiteral();
literal.setLiteralValue("Hello");
infixExpression.setLeftOperand(literal);
literal = ast.newStringLiteral();
literal.setLiteralValue(" world");
infixExpression.setRightOperand(literal);
methodInvocation.arguments().add(infixExpression);
ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
block.statements().add(expressionStatement);
methodDeclaration.setBody(block);
type.bodyDeclarations().add(methodDeclaration);
unit.types().add(type);
You may take a look at this. It uses Java Model, which means you will need to create a plug-in to make it work.
// create a project with name "TESTJDT"
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject project = root.getProject("TESTJDT");
project.create(null);
project.open(null);
//set the Java nature
IProjectDescription description = project.getDescription();
description.setNatureIds(new String[] { JavaCore.NATURE_ID });
//create the project
project.setDescription(description, null);
IJavaProject javaProject = JavaCore.create(project);
//set the build path
IClasspathEntry[] buildPath = {
JavaCore.newSourceEntry(project.getFullPath().append("src")),
JavaRuntime.getDefaultJREContainerEntry() };
javaProject.setRawClasspath(buildPath, project.getFullPath().append(
"bin"), null);
//create folder by using resources package
IFolder folder = project.getFolder("src");
folder.create(true, true, null);
//Add folder to Java element
IPackageFragmentRoot srcFolder = javaProject
.getPackageFragmentRoot(folder);
//create package fragment
IPackageFragment fragment = srcFolder.createPackageFragment(
"com.programcreek", true, null);
//init code string and create compilation unit
String str = "package com.programcreek;" + "\n"
+ "public class Test {" + "\n" + " private String name;"
+ "\n" + "}";
ICompilationUnit cu = fragment.createCompilationUnit("Test.java", str,
false, null);
//create a field
IType type = cu.getType("Test");
type.createField("private String age;", null, true, null);