mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-30 20:34:04 -04:00 
			
		
		
		
	added files via upload
This commit is contained in:
		
							
								
								
									
										209
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| // | ||||
| // Taken from https://github.com/llvm-mirror/lldb/blob/master/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h | ||||
| // by Tanner Bennett on 03/03/2019 with minimal modifications. | ||||
| // | ||||
|  | ||||
| //===-- ActivityStreamAPI.h -------------------------------------*- C++ -*-===// | ||||
| // | ||||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
| // See https://llvm.org/LICENSE.txt for license information. | ||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
|  | ||||
| #ifndef ActivityStreamSPI_h | ||||
| #define ActivityStreamSPI_h | ||||
|  | ||||
| #include <Foundation/Foundation.h> | ||||
|  | ||||
| #include <sys/time.h> | ||||
| // #include <xpc/xpc.h> | ||||
|  | ||||
| /* By default, XPC objects are declared as Objective-C types when building with | ||||
|  * an Objective-C compiler. This allows them to participate in ARC, in RR | ||||
|  * management by the Blocks runtime and in leaks checking by the static | ||||
|  * analyzer, and enables them to be added to Cocoa collections. | ||||
|  * | ||||
|  * See <os/object.h> for details. | ||||
|  */ | ||||
| #if !TARGET_OS_MACCATALYST | ||||
| #if OS_OBJECT_USE_OBJC | ||||
| OS_OBJECT_DECL(xpc_object); | ||||
| #else | ||||
| typedef void * xpc_object_t; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #define OS_ACTIVITY_MAX_CALLSTACK 32 | ||||
|  | ||||
| // Enums | ||||
|  | ||||
| typedef NS_ENUM(uint32_t, os_activity_stream_flag_t) { | ||||
|     OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001, | ||||
|     OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002, | ||||
|     OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004, | ||||
|     OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008, | ||||
|     OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010, | ||||
|     OS_ACTIVITY_STREAM_DEBUG = 0x00000020, | ||||
|     OS_ACTIVITY_STREAM_BUFFERED = 0x00000040, | ||||
|     OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080, | ||||
|     OS_ACTIVITY_STREAM_INFO = 0x00000100, | ||||
|     OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200, | ||||
|     OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200 | ||||
| }; | ||||
|  | ||||
| typedef NS_ENUM(uint32_t, os_activity_stream_type_t) { | ||||
|     OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201, | ||||
|     OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202, | ||||
|     OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203, | ||||
|      | ||||
|     OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300, | ||||
|      | ||||
|     OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400, | ||||
|     OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480, | ||||
|      | ||||
|     OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601, | ||||
|     OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602, | ||||
|     OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603, | ||||
|      | ||||
|     OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00, | ||||
| }; | ||||
|  | ||||
| typedef NS_ENUM(uint32_t, os_activity_stream_event_t) { | ||||
|     OS_ACTIVITY_STREAM_EVENT_STARTED = 1, | ||||
|     OS_ACTIVITY_STREAM_EVENT_STOPPED = 2, | ||||
|     OS_ACTIVITY_STREAM_EVENT_FAILED = 3, | ||||
|     OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4, | ||||
|     OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5, | ||||
| }; | ||||
|  | ||||
| // Types | ||||
|  | ||||
| typedef uint64_t os_activity_id_t; | ||||
| typedef struct os_activity_stream_s *os_activity_stream_t; | ||||
| typedef struct os_activity_stream_entry_s *os_activity_stream_entry_t; | ||||
|  | ||||
| #define OS_ACTIVITY_STREAM_COMMON()                                            \ | ||||
| uint64_t trace_id;                                                           \ | ||||
| uint64_t timestamp;                                                          \ | ||||
| uint64_t thread;                                                             \ | ||||
| const uint8_t *image_uuid;                                                   \ | ||||
| const char *image_path;                                                      \ | ||||
| struct timeval tv_gmt;                                                       \ | ||||
| struct timezone tz;                                                          \ | ||||
| uint32_t offset | ||||
|  | ||||
| typedef struct os_activity_stream_common_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
| } * os_activity_stream_common_t; | ||||
|  | ||||
| struct os_activity_create_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     const char *name; | ||||
|     os_activity_id_t creator_aid; | ||||
|     uint64_t unique_pid; | ||||
| }; | ||||
|  | ||||
| struct os_activity_transition_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     os_activity_id_t transition_id; | ||||
| }; | ||||
|  | ||||
| typedef struct os_log_message_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     const char *format; | ||||
|     const uint8_t *buffer; | ||||
|     size_t buffer_sz; | ||||
|     const uint8_t *privdata; | ||||
|     size_t privdata_sz; | ||||
|     const char *subsystem; | ||||
|     const char *category; | ||||
|     uint32_t oversize_id; | ||||
|     uint8_t ttl; | ||||
|     bool persisted; | ||||
| } * os_log_message_t; | ||||
|  | ||||
| typedef struct os_trace_message_v2_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     const char *format; | ||||
|     const void *buffer; | ||||
|     size_t bufferLen; | ||||
|     xpc_object_t __unsafe_unretained payload; | ||||
| } * os_trace_message_v2_t; | ||||
|  | ||||
| typedef struct os_activity_useraction_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     const char *action; | ||||
|     bool persisted; | ||||
| } * os_activity_useraction_t; | ||||
|  | ||||
| typedef struct os_signpost_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     const char *format; | ||||
|     const uint8_t *buffer; | ||||
|     size_t buffer_sz; | ||||
|     const uint8_t *privdata; | ||||
|     size_t privdata_sz; | ||||
|     const char *subsystem; | ||||
|     const char *category; | ||||
|     uint64_t duration_nsec; | ||||
|     uint32_t callstack_depth; | ||||
|     uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK]; | ||||
| } * os_signpost_t; | ||||
|  | ||||
| typedef struct os_activity_statedump_s { | ||||
|     OS_ACTIVITY_STREAM_COMMON(); | ||||
|     char *message; | ||||
|     size_t message_size; | ||||
|     char image_path_buffer[PATH_MAX]; | ||||
| } * os_activity_statedump_t; | ||||
|  | ||||
| struct os_activity_stream_entry_s { | ||||
|     os_activity_stream_type_t type; | ||||
|      | ||||
|     // information about the process streaming the data | ||||
|     pid_t pid; | ||||
|     uint64_t proc_id; | ||||
|     const uint8_t *proc_imageuuid; | ||||
|     const char *proc_imagepath; | ||||
|      | ||||
|     // the activity associated with this streamed event | ||||
|     os_activity_id_t activity_id; | ||||
|     os_activity_id_t parent_id; | ||||
|      | ||||
|     union { | ||||
|         struct os_activity_stream_common_s common; | ||||
|         struct os_activity_create_s activity_create; | ||||
|         struct os_activity_transition_s activity_transition; | ||||
|         struct os_log_message_s log_message; | ||||
|         struct os_trace_message_v2_s trace_message; | ||||
|         struct os_activity_useraction_s useraction; | ||||
|         struct os_signpost_s signpost; | ||||
|         struct os_activity_statedump_s statedump; | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| // Blocks | ||||
|  | ||||
| typedef bool (^os_activity_stream_block_t)(os_activity_stream_entry_t entry, | ||||
|                                            int error); | ||||
|  | ||||
| typedef void (^os_activity_stream_event_block_t)( | ||||
|                                                  os_activity_stream_t stream, os_activity_stream_event_t event); | ||||
|  | ||||
| // SPI entry point prototypes | ||||
|  | ||||
| typedef os_activity_stream_t (*os_activity_stream_for_pid_t)( | ||||
|                                                              pid_t pid, os_activity_stream_flag_t flags, | ||||
|                                                              os_activity_stream_block_t stream_block); | ||||
|  | ||||
| typedef void (*os_activity_stream_resume_t)(os_activity_stream_t stream); | ||||
|  | ||||
| typedef void (*os_activity_stream_cancel_t)(os_activity_stream_t stream); | ||||
|  | ||||
| typedef char *(*os_log_copy_formatted_message_t)(os_log_message_t log_message); | ||||
|  | ||||
| typedef void (*os_activity_stream_set_event_handler_t)( | ||||
|                                                        os_activity_stream_t stream, os_activity_stream_event_block_t block); | ||||
|  | ||||
| #endif /* ActivityStreamSPI_h */ | ||||
| @@ -0,0 +1,18 @@ | ||||
| // | ||||
| //  FLEXASLLogController.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Tanner on 3/14/19. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXLogController.h" | ||||
|  | ||||
| @interface FLEXASLLogController : NSObject <FLEXLogController> | ||||
|  | ||||
| /// Guaranteed to call back on the main thread. | ||||
| + (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler; | ||||
|  | ||||
| - (BOOL)startMonitoring; | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,147 @@ | ||||
| // | ||||
| //  FLEXASLLogController.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Tanner on 3/14/19. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXASLLogController.h" | ||||
| #import <asl.h> | ||||
|  | ||||
| // Querying the ASL is much slower in the simulator. We need a longer polling interval to keep things responsive. | ||||
| #if TARGET_IPHONE_SIMULATOR | ||||
|     #define updateInterval 5.0 | ||||
| #else | ||||
|     #define updateInterval 0.5 | ||||
| #endif | ||||
|  | ||||
| @interface FLEXASLLogController () | ||||
|  | ||||
| @property (nonatomic, readonly) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *); | ||||
|  | ||||
| @property (nonatomic) NSTimer *logUpdateTimer; | ||||
| @property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers; | ||||
|  | ||||
| // ASL stuff | ||||
|  | ||||
| @property (nonatomic) NSUInteger heapSize; | ||||
| @property (nonatomic) dispatch_queue_t logQueue; | ||||
| @property (nonatomic) dispatch_io_t io; | ||||
| @property (nonatomic) NSString *remaining; | ||||
| @property (nonatomic) int stderror; | ||||
| @property (nonatomic) NSString *lastTimestamp; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @implementation FLEXASLLogController | ||||
|  | ||||
| + (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler { | ||||
|     return [[self alloc] initWithUpdateHandler:newMessagesHandler]; | ||||
| } | ||||
|  | ||||
| - (id)initWithUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler { | ||||
|     NSParameterAssert(newMessagesHandler); | ||||
|  | ||||
|     self = [super init]; | ||||
|     if (self) { | ||||
|         _updateHandler = newMessagesHandler; | ||||
|         _logMessageIdentifiers = [NSMutableIndexSet new]; | ||||
|         self.logUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateInterval | ||||
|                                                                target:self | ||||
|                                                              selector:@selector(updateLogMessages) | ||||
|                                                              userInfo:nil | ||||
|                                                               repeats:YES]; | ||||
|     } | ||||
|  | ||||
|     return self; | ||||
| } | ||||
|  | ||||
| - (void)dealloc { | ||||
|     [self.logUpdateTimer invalidate]; | ||||
| } | ||||
|  | ||||
| - (BOOL)startMonitoring { | ||||
|     [self.logUpdateTimer fire]; | ||||
|     return YES; | ||||
| } | ||||
|  | ||||
| - (void)updateLogMessages { | ||||
|     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||||
|         NSArray<FLEXSystemLogMessage *> *newMessages; | ||||
|         @synchronized (self) { | ||||
|             newMessages = [self newLogMessagesForCurrentProcess]; | ||||
|             if (!newMessages.count) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             for (FLEXSystemLogMessage *message in newMessages) { | ||||
|                 [self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID]; | ||||
|             } | ||||
|  | ||||
|             self.lastTimestamp = @(asl_get(newMessages.lastObject.aslMessage, ASL_KEY_TIME) ?: "null"); | ||||
|         } | ||||
|  | ||||
|         dispatch_async(dispatch_get_main_queue(), ^{ | ||||
|             self.updateHandler(newMessages); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| #pragma mark - Log Message Fetching | ||||
|  | ||||
| - (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess { | ||||
|     if (!self.logMessageIdentifiers.count) { | ||||
|         return [self allLogMessagesForCurrentProcess]; | ||||
|     } | ||||
|  | ||||
|     aslresponse response = [self ASLMessageListForCurrentProcess]; | ||||
|     aslmsg aslMessage = NULL; | ||||
|  | ||||
|     NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray new]; | ||||
|  | ||||
|     while ((aslMessage = asl_next(response))) { | ||||
|         NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID)); | ||||
|         if (![self.logMessageIdentifiers containsIndex:messageID]) { | ||||
|             [newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     asl_release(response); | ||||
|     return newMessages; | ||||
| } | ||||
|  | ||||
| - (aslresponse)ASLMessageListForCurrentProcess { | ||||
|     static NSString *pidString = nil; | ||||
|     if (!pidString) { | ||||
|         pidString = @([NSProcessInfo.processInfo processIdentifier]).stringValue; | ||||
|     } | ||||
|  | ||||
|     // Create system log query object. | ||||
|     asl_object_t query = asl_new(ASL_TYPE_QUERY); | ||||
|  | ||||
|     // Filter for messages from the current process. | ||||
|     // Note that this appears to happen by default on device, but is required in the simulator. | ||||
|     asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL); | ||||
|     // Filter for messages after the last retrieved message. | ||||
|     if (self.lastTimestamp) { | ||||
|         asl_set_query(query, ASL_KEY_TIME, self.lastTimestamp.UTF8String, ASL_QUERY_OP_GREATER); | ||||
|     } | ||||
|  | ||||
|     return asl_search(NULL, query); | ||||
| } | ||||
|  | ||||
| - (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess { | ||||
|     aslresponse response = [self ASLMessageListForCurrentProcess]; | ||||
|     aslmsg aslMessage = NULL; | ||||
|  | ||||
|     NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray new]; | ||||
|     while ((aslMessage = asl_next(response))) { | ||||
|         [logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]]; | ||||
|     } | ||||
|     asl_release(response); | ||||
|  | ||||
|     return logMessages; | ||||
| } | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,19 @@ | ||||
| // | ||||
| //  FLEXLogController.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Tanner on 3/17/19. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import <Foundation/Foundation.h> | ||||
| #import "FLEXSystemLogMessage.h" | ||||
|  | ||||
| @protocol FLEXLogController <NSObject> | ||||
|  | ||||
| /// Guaranteed to call back on the main thread. | ||||
| + (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler; | ||||
|  | ||||
| - (BOOL)startMonitoring; | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,27 @@ | ||||
| // | ||||
| //  FLEXOSLogController.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Tanner on 12/19/18. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXLogController.h" | ||||
|  | ||||
| #define FLEXOSLogAvailable() (NSProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 10) | ||||
|  | ||||
| /// The log controller used for iOS 10 and up. | ||||
| @interface FLEXOSLogController : NSObject <FLEXLogController> | ||||
|  | ||||
| + (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler; | ||||
|  | ||||
| - (BOOL)startMonitoring; | ||||
|  | ||||
| /// Whether log messages are to be recorded and kept in-memory in the background. | ||||
| /// You do not need to initialize this value, only change it. | ||||
| @property (nonatomic) BOOL persistent; | ||||
| /// Used mostly internally, but also used by the log VC to persist messages | ||||
| /// that were created prior to enabling persistence. | ||||
| @property (nonatomic) NSMutableArray<FLEXSystemLogMessage *> *messages; | ||||
|  | ||||
| @end | ||||
							
								
								
									
										214
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXOSLogController.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXOSLogController.m
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | ||||
| // | ||||
| //  FLEXOSLogController.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Tanner on 12/19/18. | ||||
| //  Copyright © 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXOSLogController.h" | ||||
| #import "NSUserDefaults+FLEX.h" | ||||
| #include <dlfcn.h> | ||||
| #include "ActivityStreamAPI.h" | ||||
|  | ||||
| static os_activity_stream_for_pid_t OSActivityStreamForPID; | ||||
| static os_activity_stream_resume_t OSActivityStreamResume; | ||||
| static os_activity_stream_cancel_t OSActivityStreamCancel; | ||||
| static os_log_copy_formatted_message_t OSLogCopyFormattedMessage; | ||||
| static os_activity_stream_set_event_handler_t OSActivityStreamSetEventHandler; | ||||
| static int (*proc_name)(int, char *, unsigned int); | ||||
| static int (*proc_listpids)(uint32_t, uint32_t, void*, int); | ||||
| static uint8_t (*OSLogGetType)(void *); | ||||
|  | ||||
| @interface FLEXOSLogController () | ||||
|  | ||||
| + (FLEXOSLogController *)sharedLogController; | ||||
|  | ||||
| @property (nonatomic) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *); | ||||
|  | ||||
| @property (nonatomic) BOOL canPrint; | ||||
| @property (nonatomic) int filterPid; | ||||
| @property (nonatomic) BOOL levelInfo; | ||||
| @property (nonatomic) BOOL subsystemInfo; | ||||
|  | ||||
| @property (nonatomic) os_activity_stream_t stream; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @implementation FLEXOSLogController | ||||
|  | ||||
| + (void)load { | ||||
|     // Persist logs when the app launches on iOS 10 if we have persistent logs turned on | ||||
|     if (FLEXOSLogAvailable()) { | ||||
|         if (NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages) { | ||||
|             [self sharedLogController].persistent = YES; | ||||
|             [[self sharedLogController] startMonitoring]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| + (instancetype)sharedLogController { | ||||
|     static FLEXOSLogController *shared = nil; | ||||
|     static dispatch_once_t onceToken; | ||||
|     dispatch_once(&onceToken, ^{ | ||||
|         shared = [self new]; | ||||
|     }); | ||||
|      | ||||
|     return shared; | ||||
| } | ||||
|  | ||||
| + (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler { | ||||
|     FLEXOSLogController *shared = [self sharedLogController]; | ||||
|     shared.updateHandler = newMessagesHandler; | ||||
|     return shared; | ||||
| } | ||||
|  | ||||
| - (id)init { | ||||
|     NSAssert(FLEXOSLogAvailable(), @"os_log is only available on iOS 10 and up"); | ||||
|  | ||||
|     self = [super init]; | ||||
|     if (self) { | ||||
|         _filterPid = NSProcessInfo.processInfo.processIdentifier; | ||||
|         _levelInfo = NO; | ||||
|         _subsystemInfo = NO; | ||||
|     } | ||||
|      | ||||
|     return self; | ||||
| } | ||||
|  | ||||
| - (void)dealloc { | ||||
|     OSActivityStreamCancel(self.stream); | ||||
|     _stream = nil; | ||||
| } | ||||
|  | ||||
| - (void)setPersistent:(BOOL)persistent { | ||||
|     if (_persistent == persistent) return; | ||||
|      | ||||
|     _persistent = persistent; | ||||
|     self.messages = persistent ? [NSMutableArray new] : nil; | ||||
| } | ||||
|  | ||||
| - (BOOL)startMonitoring { | ||||
|     if (![self lookupSPICalls]) { | ||||
|         // >= iOS 10 is required | ||||
|         return NO; | ||||
|     } | ||||
|      | ||||
|     // Are we already monitoring? | ||||
|     if (self.stream) { | ||||
|         // Should we send out the "persisted" messages? | ||||
|         if (self.updateHandler && self.messages.count) { | ||||
|             dispatch_async(dispatch_get_main_queue(), ^{ | ||||
|                 self.updateHandler(self.messages); | ||||
|             }); | ||||
|         } | ||||
|          | ||||
|         return YES; | ||||
|     } | ||||
|  | ||||
|     // Stream entry handler | ||||
|     os_activity_stream_block_t block = ^bool(os_activity_stream_entry_t entry, int error) { | ||||
|         return [self handleStreamEntry:entry error:error]; | ||||
|     }; | ||||
|  | ||||
|     // Controls which types of messages we see | ||||
|     // 'Historical' appears to just show NSLog stuff | ||||
|     uint32_t activity_stream_flags = OS_ACTIVITY_STREAM_HISTORICAL; | ||||
|     activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY; | ||||
| //    activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY; | ||||
|  | ||||
|     self.stream = OSActivityStreamForPID(self.filterPid, activity_stream_flags, block); | ||||
|  | ||||
|     // Specify the stream-related event handler | ||||
|     OSActivityStreamSetEventHandler(self.stream, [self streamEventHandlerBlock]); | ||||
|     // Start the stream | ||||
|     OSActivityStreamResume(self.stream); | ||||
|  | ||||
|     return YES; | ||||
| } | ||||
|  | ||||
| - (BOOL)lookupSPICalls { | ||||
|     static BOOL hasSPI = NO; | ||||
|     static dispatch_once_t onceToken; | ||||
|     dispatch_once(&onceToken, ^{ | ||||
|         void *handle = dlopen("/System/Library/PrivateFrameworks/LoggingSupport.framework/LoggingSupport", RTLD_NOW); | ||||
|  | ||||
|         OSActivityStreamForPID = (os_activity_stream_for_pid_t)dlsym(handle, "os_activity_stream_for_pid"); | ||||
|         OSActivityStreamResume = (os_activity_stream_resume_t)dlsym(handle, "os_activity_stream_resume"); | ||||
|         OSActivityStreamCancel = (os_activity_stream_cancel_t)dlsym(handle, "os_activity_stream_cancel"); | ||||
|         OSLogCopyFormattedMessage = (os_log_copy_formatted_message_t)dlsym(handle, "os_log_copy_formatted_message"); | ||||
|         OSActivityStreamSetEventHandler = (os_activity_stream_set_event_handler_t)dlsym(handle, "os_activity_stream_set_event_handler"); | ||||
|         proc_name = (int(*)(int, char *, unsigned int))dlsym(handle, "proc_name"); | ||||
|         proc_listpids = (int(*)(uint32_t, uint32_t, void*, int))dlsym(handle, "proc_listpids"); | ||||
|         OSLogGetType = (uint8_t(*)(void *))dlsym(handle, "os_log_get_type"); | ||||
|  | ||||
|         hasSPI = (OSActivityStreamForPID != NULL) && | ||||
|                 (OSActivityStreamResume != NULL) && | ||||
|                 (OSActivityStreamCancel != NULL) && | ||||
|                 (OSLogCopyFormattedMessage != NULL) && | ||||
|                 (OSActivityStreamSetEventHandler != NULL) && | ||||
|                 (OSLogGetType != NULL) && | ||||
|                 (proc_name != NULL); | ||||
|     }); | ||||
|      | ||||
|     return hasSPI; | ||||
| } | ||||
|  | ||||
| - (BOOL)handleStreamEntry:(os_activity_stream_entry_t)entry error:(int)error { | ||||
|     if (!self.canPrint || (self.filterPid != -1 && entry->pid != self.filterPid)) { | ||||
|         return YES; | ||||
|     } | ||||
|  | ||||
|     if (!error && entry) { | ||||
|         if (entry->type == OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE || | ||||
|             entry->type == OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE) { | ||||
|             os_log_message_t log_message = &entry->log_message; | ||||
|              | ||||
|             // Get date | ||||
|             NSDate *date = [NSDate dateWithTimeIntervalSince1970:log_message->tv_gmt.tv_sec]; | ||||
|              | ||||
|             // Get log message text | ||||
|             // https://github.com/limneos/oslog/issues/1 | ||||
|             // https://github.com/FLEXTool/FLEX/issues/564 | ||||
|             const char *messageText = OSLogCopyFormattedMessage(log_message) ?: ""; | ||||
|  | ||||
|             // move messageText from stack to heap | ||||
|             NSString *msg = [NSString stringWithUTF8String:messageText]; | ||||
|  | ||||
|             dispatch_async(dispatch_get_main_queue(), ^{ | ||||
|                 FLEXSystemLogMessage *message = [FLEXSystemLogMessage logMessageFromDate:date text:msg]; | ||||
|                 if (self.persistent) { | ||||
|                     [self.messages addObject:message]; | ||||
|                 } | ||||
|                 if (self.updateHandler) { | ||||
|                     self.updateHandler(@[message]); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return YES; | ||||
| } | ||||
|  | ||||
| - (os_activity_stream_event_block_t)streamEventHandlerBlock { | ||||
|     return [^void(os_activity_stream_t stream, os_activity_stream_event_t event) { | ||||
|         switch (event) { | ||||
|             case OS_ACTIVITY_STREAM_EVENT_STARTED: | ||||
|                 self.canPrint = YES; | ||||
|                 break; | ||||
|             case OS_ACTIVITY_STREAM_EVENT_STOPPED: | ||||
|                 break; | ||||
|             case OS_ACTIVITY_STREAM_EVENT_FAILED: | ||||
|                 break; | ||||
|             case OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED: | ||||
|                 break; | ||||
|             case OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED: | ||||
|                 break; | ||||
|             default: | ||||
|                 printf("=== Unhandled case ===\n"); | ||||
|                 break; | ||||
|         } | ||||
|     } copy]; | ||||
| } | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,23 @@ | ||||
| // | ||||
| //  FLEXSystemLogCell.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/25/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXTableViewCell.h" | ||||
|  | ||||
| @class FLEXSystemLogMessage; | ||||
|  | ||||
| extern NSString *const kFLEXSystemLogCellIdentifier; | ||||
|  | ||||
| @interface FLEXSystemLogCell : FLEXTableViewCell | ||||
|  | ||||
| @property (nonatomic) FLEXSystemLogMessage *logMessage; | ||||
| @property (nonatomic, copy) NSString *highlightedText; | ||||
|  | ||||
| + (NSString *)displayedTextForLogMessage:(FLEXSystemLogMessage *)logMessage; | ||||
| + (CGFloat)preferredHeightForLogMessage:(FLEXSystemLogMessage *)logMessage inWidth:(CGFloat)width; | ||||
|  | ||||
| @end | ||||
							
								
								
									
										119
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.m
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| // | ||||
| //  FLEXSystemLogCell.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/25/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXSystemLogCell.h" | ||||
| #import "FLEXSystemLogMessage.h" | ||||
| #import "UIFont+FLEX.h" | ||||
|  | ||||
| NSString *const kFLEXSystemLogCellIdentifier = @"FLEXSystemLogCellIdentifier"; | ||||
|  | ||||
| @interface FLEXSystemLogCell () | ||||
|  | ||||
| @property (nonatomic) UILabel *logMessageLabel; | ||||
| @property (nonatomic) NSAttributedString *logMessageAttributedText; | ||||
|  | ||||
| @end | ||||
|  | ||||
| @implementation FLEXSystemLogCell | ||||
|  | ||||
| - (void)postInit { | ||||
|     [super postInit]; | ||||
|      | ||||
|     self.logMessageLabel = [UILabel new]; | ||||
|     self.logMessageLabel.numberOfLines = 0; | ||||
|     self.separatorInset = UIEdgeInsetsZero; | ||||
|     self.selectionStyle = UITableViewCellSelectionStyleNone; | ||||
|     [self.contentView addSubview:self.logMessageLabel]; | ||||
| } | ||||
|  | ||||
| - (void)setLogMessage:(FLEXSystemLogMessage *)logMessage { | ||||
|     if (![_logMessage isEqual:logMessage]) { | ||||
|         _logMessage = logMessage; | ||||
|         self.logMessageAttributedText = nil; | ||||
|         [self setNeedsLayout]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (void)setHighlightedText:(NSString *)highlightedText { | ||||
|     if (![_highlightedText isEqual:highlightedText]) { | ||||
|         _highlightedText = highlightedText; | ||||
|         self.logMessageAttributedText = nil; | ||||
|         [self setNeedsLayout]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (NSAttributedString *)logMessageAttributedText { | ||||
|     if (!_logMessageAttributedText) { | ||||
|         _logMessageAttributedText = [[self class] attributedTextForLogMessage:self.logMessage highlightedText:self.highlightedText]; | ||||
|     } | ||||
|     return _logMessageAttributedText; | ||||
| } | ||||
|  | ||||
| static const UIEdgeInsets kFLEXLogMessageCellInsets = {10.0, 10.0, 10.0, 10.0}; | ||||
|  | ||||
| - (void)layoutSubviews { | ||||
|     [super layoutSubviews]; | ||||
|  | ||||
|     self.logMessageLabel.attributedText = self.logMessageAttributedText; | ||||
|     self.logMessageLabel.frame = UIEdgeInsetsInsetRect(self.contentView.bounds, kFLEXLogMessageCellInsets); | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - Stateless helpers | ||||
|  | ||||
| + (NSAttributedString *)attributedTextForLogMessage:(FLEXSystemLogMessage *)logMessage highlightedText:(NSString *)highlightedText { | ||||
|     NSString *text = [self displayedTextForLogMessage:logMessage]; | ||||
|     NSDictionary<NSString *, id> *attributes = @{ NSFontAttributeName : UIFont.flex_codeFont }; | ||||
|     NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes]; | ||||
|  | ||||
|     if (highlightedText.length > 0) { | ||||
|         NSMutableAttributedString *mutableAttributedText = attributedText.mutableCopy; | ||||
|         NSMutableDictionary<NSString *, id> *highlightAttributes = attributes.mutableCopy; | ||||
|         highlightAttributes[NSBackgroundColorAttributeName] = UIColor.yellowColor; | ||||
|          | ||||
|         NSRange remainingSearchRange = NSMakeRange(0, text.length); | ||||
|         while (remainingSearchRange.location < text.length) { | ||||
|             remainingSearchRange.length = text.length - remainingSearchRange.location; | ||||
|             NSRange foundRange = [text rangeOfString:highlightedText options:NSCaseInsensitiveSearch range:remainingSearchRange]; | ||||
|             if (foundRange.location != NSNotFound) { | ||||
|                 remainingSearchRange.location = foundRange.location + foundRange.length; | ||||
|                 [mutableAttributedText setAttributes:highlightAttributes range:foundRange]; | ||||
|             } else { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         attributedText = mutableAttributedText; | ||||
|     } | ||||
|  | ||||
|     return attributedText; | ||||
| } | ||||
|  | ||||
| + (NSString *)displayedTextForLogMessage:(FLEXSystemLogMessage *)logMessage { | ||||
|     return [NSString stringWithFormat:@"%@: %@", [self logTimeStringFromDate:logMessage.date], logMessage.messageText]; | ||||
| } | ||||
|  | ||||
| + (CGFloat)preferredHeightForLogMessage:(FLEXSystemLogMessage *)logMessage inWidth:(CGFloat)width { | ||||
|     UIEdgeInsets insets = kFLEXLogMessageCellInsets; | ||||
|     CGFloat availableWidth = width - insets.left - insets.right; | ||||
|     NSAttributedString *attributedLogText = [self attributedTextForLogMessage:logMessage highlightedText:nil]; | ||||
|     CGSize labelSize = [attributedLogText boundingRectWithSize:CGSizeMake(availableWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size; | ||||
|     return labelSize.height + insets.top + insets.bottom; | ||||
| } | ||||
|  | ||||
| + (NSString *)logTimeStringFromDate:(NSDate *)date { | ||||
|     static NSDateFormatter *formatter = nil; | ||||
|     static dispatch_once_t onceToken; | ||||
|     dispatch_once(&onceToken, ^{ | ||||
|         formatter = [NSDateFormatter new]; | ||||
|         formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; | ||||
|     }); | ||||
|  | ||||
|     return [formatter stringFromDate:date]; | ||||
| } | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,30 @@ | ||||
| // | ||||
| //  FLEXSystemLogMessage.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/25/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import <Foundation/Foundation.h> | ||||
| #import <asl.h> | ||||
| #import "ActivityStreamAPI.h" | ||||
|  | ||||
| NS_ASSUME_NONNULL_BEGIN | ||||
|  | ||||
| @interface FLEXSystemLogMessage : NSObject | ||||
|  | ||||
| + (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage; | ||||
| + (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text; | ||||
|  | ||||
| // ASL specific properties | ||||
| @property (nonatomic, readonly, nullable) NSString *sender; | ||||
| @property (nonatomic, readonly, nullable) aslmsg aslMessage; | ||||
|  | ||||
| @property (nonatomic, readonly) NSDate *date; | ||||
| @property (nonatomic, readonly) NSString *messageText; | ||||
| @property (nonatomic, readonly) long long messageID; | ||||
|  | ||||
| @end | ||||
|  | ||||
| NS_ASSUME_NONNULL_END | ||||
| @@ -0,0 +1,88 @@ | ||||
| // | ||||
| //  FLEXSystemLogMessage.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/25/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXSystemLogMessage.h" | ||||
|  | ||||
| @implementation FLEXSystemLogMessage | ||||
|  | ||||
| + (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage { | ||||
|     NSDate *date = nil; | ||||
|     NSString *sender = nil, *text = nil; | ||||
|     long long identifier = 0; | ||||
|  | ||||
|     const char *timestamp = asl_get(aslMessage, ASL_KEY_TIME); | ||||
|     if (timestamp) { | ||||
|         NSTimeInterval timeInterval = [@(timestamp) integerValue]; | ||||
|         const char *nanoseconds = asl_get(aslMessage, ASL_KEY_TIME_NSEC); | ||||
|         if (nanoseconds) { | ||||
|             timeInterval += [@(nanoseconds) doubleValue] / NSEC_PER_SEC; | ||||
|         } | ||||
|         date = [NSDate dateWithTimeIntervalSince1970:timeInterval]; | ||||
|     } | ||||
|  | ||||
|     const char *s = asl_get(aslMessage, ASL_KEY_SENDER); | ||||
|     if (s) { | ||||
|         sender = @(s); | ||||
|     } | ||||
|  | ||||
|     const char *messageText = asl_get(aslMessage, ASL_KEY_MSG); | ||||
|     if (messageText) { | ||||
|         text = @(messageText); | ||||
|     } | ||||
|  | ||||
|     const char *messageID = asl_get(aslMessage, ASL_KEY_MSG_ID); | ||||
|     if (messageID) { | ||||
|         identifier = [@(messageID) longLongValue]; | ||||
|     } | ||||
|  | ||||
|     FLEXSystemLogMessage *message = [[self alloc] initWithDate:date sender:sender text:text messageID:identifier]; | ||||
|     message->_aslMessage = aslMessage; | ||||
|     return message; | ||||
| } | ||||
|  | ||||
| + (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text { | ||||
|     return [[self alloc] initWithDate:date sender:nil text:text messageID:0]; | ||||
| } | ||||
|  | ||||
| - (id)initWithDate:(NSDate *)date sender:(NSString *)sender text:(NSString *)text messageID:(long long)identifier { | ||||
|     self = [super init]; | ||||
|     if (self) { | ||||
|         _date = date; | ||||
|         _sender = sender; | ||||
|         _messageText = text; | ||||
|         _messageID = identifier; | ||||
|     } | ||||
|  | ||||
|     return self; | ||||
| } | ||||
|  | ||||
| - (BOOL)isEqual:(id)object { | ||||
|     if ([object isKindOfClass:[self class]]) { | ||||
|         if (self.messageID) { | ||||
|             // Only ASL uses messageID, otherwise it is 0 | ||||
|             return self.messageID == [object messageID]; | ||||
|         } else { | ||||
|             // Test message texts and dates for OS Log | ||||
|             return [self.messageText isEqual:[object messageText]] && | ||||
|                     [self.date isEqualToDate:[object date]]; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return NO; | ||||
| } | ||||
|  | ||||
| - (NSUInteger)hash { | ||||
|     return (NSUInteger)self.messageID; | ||||
| } | ||||
|  | ||||
| - (NSString *)description { | ||||
|     NSString *escaped = [self.messageText stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; | ||||
|     return [NSString stringWithFormat:@"(%@) %@", @(self.messageText.length), escaped]; | ||||
| } | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,14 @@ | ||||
| // | ||||
| //  FLEXSystemLogViewController.h | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/19/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXFilteringTableViewController.h" | ||||
| #import "FLEXGlobalsEntry.h" | ||||
|  | ||||
| @interface FLEXSystemLogViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry> | ||||
|  | ||||
| @end | ||||
| @@ -0,0 +1,293 @@ | ||||
| // | ||||
| //  FLEXSystemLogViewController.m | ||||
| //  FLEX | ||||
| // | ||||
| //  Created by Ryan Olson on 1/19/15. | ||||
| //  Copyright (c) 2020 FLEX Team. All rights reserved. | ||||
| // | ||||
|  | ||||
| #import "FLEXSystemLogViewController.h" | ||||
| #import "FLEXASLLogController.h" | ||||
| #import "FLEXOSLogController.h" | ||||
| #import "FLEXSystemLogCell.h" | ||||
| #import "FLEXMutableListSection.h" | ||||
| #import "FLEXUtility.h" | ||||
| #import "FLEXColor.h" | ||||
| #import "FLEXResources.h" | ||||
| #import "UIBarButtonItem+FLEX.h" | ||||
| #import "NSUserDefaults+FLEX.h" | ||||
| #import "flex_fishhook.h" | ||||
| #import <dlfcn.h> | ||||
|  | ||||
| @interface FLEXSystemLogViewController () | ||||
|  | ||||
| @property (nonatomic, readonly) FLEXMutableListSection<FLEXSystemLogMessage *> *logMessages; | ||||
| @property (nonatomic, readonly) id<FLEXLogController> logController; | ||||
|  | ||||
| @end | ||||
|  | ||||
| static void (*MSHookFunction)(void *symbol, void *replace, void **result); | ||||
|  | ||||
| static BOOL FLEXDidHookNSLog = NO; | ||||
| static BOOL FLEXNSLogHookWorks = NO; | ||||
|  | ||||
| BOOL (*os_log_shim_enabled)(void *addr) = nil; | ||||
| BOOL (*orig_os_log_shim_enabled)(void *addr) = nil; | ||||
| static BOOL my_os_log_shim_enabled(void *addr) { | ||||
|     return NO; | ||||
| } | ||||
|  | ||||
| @implementation FLEXSystemLogViewController | ||||
|  | ||||
| #pragma mark - Initialization | ||||
|  | ||||
| + (void)load { | ||||
|     // User must opt-into disabling os_log | ||||
|     if (!NSUserDefaults.standardUserDefaults.flex_disableOSLog) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Thanks to @Ram4096 on GitHub for telling me that | ||||
|     // os_log is conditionally enabled by the SDK version | ||||
|     void *addr = __builtin_return_address(0); | ||||
|     void *libsystem_trace = dlopen("/usr/lib/system/libsystem_trace.dylib", RTLD_LAZY); | ||||
|     os_log_shim_enabled = dlsym(libsystem_trace, "os_log_shim_enabled"); | ||||
|     if (!os_log_shim_enabled) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     FLEXDidHookNSLog = flex_rebind_symbols((struct rebinding[1]) {{ | ||||
|         "os_log_shim_enabled", | ||||
|         (void *)my_os_log_shim_enabled, | ||||
|         (void **)&orig_os_log_shim_enabled | ||||
|     }}, 1) == 0; | ||||
|  | ||||
|     if (FLEXDidHookNSLog && orig_os_log_shim_enabled != nil) { | ||||
|         // Check if our rebinding worked | ||||
|         FLEXNSLogHookWorks = my_os_log_shim_enabled(addr) == NO; | ||||
|     } | ||||
|  | ||||
|     // So, just because we rebind the lazily loaded symbol for | ||||
|     // this function doesn't mean it's even going to be used. | ||||
|     // While it seems to be sufficient for the simulator, for | ||||
|     // whatever reason it is not sufficient on-device. We need | ||||
|     // to actually hook the function with something like Substrate. | ||||
|  | ||||
|     // Check if we have substrate, and if so use that instead | ||||
|     void *handle = dlopen("/usr/lib/libsubstrate.dylib", RTLD_LAZY); | ||||
|     if (handle) { | ||||
|         MSHookFunction = dlsym(handle, "MSHookFunction"); | ||||
|  | ||||
|         if (MSHookFunction) { | ||||
|             // Set the hook and check if it worked | ||||
|             void *unused; | ||||
|             MSHookFunction(os_log_shim_enabled, my_os_log_shim_enabled, &unused); | ||||
|             FLEXNSLogHookWorks = os_log_shim_enabled(addr) == NO; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (id)init { | ||||
|     return [super initWithStyle:UITableViewStylePlain]; | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - Overrides | ||||
|  | ||||
| - (void)viewDidLoad { | ||||
|     [super viewDidLoad]; | ||||
|  | ||||
|     self.showsSearchBar = YES; | ||||
|     self.pinSearchBar = YES; | ||||
|  | ||||
|     weakify(self) | ||||
|     id logHandler = ^(NSArray<FLEXSystemLogMessage *> *newMessages) { strongify(self) | ||||
|         [self handleUpdateWithNewMessages:newMessages]; | ||||
|     }; | ||||
|  | ||||
|     if (FLEXOSLogAvailable() && !FLEXNSLogHookWorks) { | ||||
|         _logController = [FLEXOSLogController withUpdateHandler:logHandler]; | ||||
|     } else { | ||||
|         _logController = [FLEXASLLogController withUpdateHandler:logHandler]; | ||||
|     } | ||||
|  | ||||
|     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; | ||||
|     self.title = @"Waiting for Logs..."; | ||||
|  | ||||
|     // Toolbar buttons // | ||||
|  | ||||
|     UIBarButtonItem *scrollDown = [UIBarButtonItem | ||||
|         flex_itemWithImage:FLEXResources.scrollToBottomIcon | ||||
|         target:self | ||||
|         action:@selector(scrollToLastRow) | ||||
|     ]; | ||||
|     UIBarButtonItem *settings = [UIBarButtonItem | ||||
|         flex_itemWithImage:FLEXResources.gearIcon | ||||
|         target:self | ||||
|         action:@selector(showLogSettings) | ||||
|     ]; | ||||
|  | ||||
|     [self addToolbarItems:@[scrollDown, settings]]; | ||||
| } | ||||
|  | ||||
| - (void)viewWillAppear:(BOOL)animated { | ||||
|     [super viewWillAppear:animated]; | ||||
|  | ||||
|     [self.logController startMonitoring]; | ||||
| } | ||||
|  | ||||
| - (NSArray<FLEXTableViewSection *> *)makeSections { weakify(self) | ||||
|     _logMessages = [FLEXMutableListSection list:@[] | ||||
|         cellConfiguration:^(FLEXSystemLogCell *cell, FLEXSystemLogMessage *message, NSInteger row) { | ||||
|             strongify(self) | ||||
|          | ||||
|             cell.logMessage = message; | ||||
|             cell.highlightedText = self.filterText; | ||||
|  | ||||
|             if (row % 2 == 0) { | ||||
|                 cell.backgroundColor = FLEXColor.primaryBackgroundColor; | ||||
|             } else { | ||||
|                 cell.backgroundColor = FLEXColor.secondaryBackgroundColor; | ||||
|             } | ||||
|         } filterMatcher:^BOOL(NSString *filterText, FLEXSystemLogMessage *message) { | ||||
|             NSString *displayedText = [FLEXSystemLogCell displayedTextForLogMessage:message]; | ||||
|             return [displayedText localizedCaseInsensitiveContainsString:filterText]; | ||||
|         } | ||||
|     ]; | ||||
|  | ||||
|     self.logMessages.cellRegistrationMapping = @{ | ||||
|         kFLEXSystemLogCellIdentifier : [FLEXSystemLogCell class] | ||||
|     }; | ||||
|  | ||||
|     return @[self.logMessages]; | ||||
| } | ||||
|  | ||||
| - (NSArray<FLEXTableViewSection *> *)nonemptySections { | ||||
|     return @[self.logMessages]; | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - Private | ||||
|  | ||||
| - (void)handleUpdateWithNewMessages:(NSArray<FLEXSystemLogMessage *> *)newMessages { | ||||
|     self.title = [self.class globalsEntryTitle:FLEXGlobalsRowSystemLog]; | ||||
|  | ||||
|     [self.logMessages mutate:^(NSMutableArray *list) { | ||||
|         [list addObjectsFromArray:newMessages]; | ||||
|     }]; | ||||
|      | ||||
|     // Re-filter messages to filter against new messages | ||||
|     if (self.filterText.length) { | ||||
|         [self updateSearchResults:self.filterText]; | ||||
|     } | ||||
|  | ||||
|     // "Follow" the log as new messages stream in if we were previously near the bottom. | ||||
|     UITableView *tv = self.tableView; | ||||
|     BOOL wasNearBottom = tv.contentOffset.y >= tv.contentSize.height - tv.frame.size.height - 100.0; | ||||
|     [self reloadData]; | ||||
|     if (wasNearBottom) { | ||||
|         [self scrollToLastRow]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (void)scrollToLastRow { | ||||
|     NSInteger numberOfRows = [self.tableView numberOfRowsInSection:0]; | ||||
|     if (numberOfRows > 0) { | ||||
|         NSIndexPath *last = [NSIndexPath indexPathForRow:numberOfRows - 1 inSection:0]; | ||||
|         [self.tableView scrollToRowAtIndexPath:last atScrollPosition:UITableViewScrollPositionBottom animated:YES]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (void)showLogSettings { | ||||
|     NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; | ||||
|     BOOL disableOSLog = defaults.flex_disableOSLog; | ||||
|     BOOL persistent = defaults.flex_cacheOSLogMessages; | ||||
|  | ||||
|     NSString *aslToggle = disableOSLog ? @"Enable os_log (default)" : @"Disable os_log"; | ||||
|     NSString *persistence = persistent ? @"Disable persistent logging" : @"Enable persistent logging"; | ||||
|  | ||||
|     NSString *title = @"System Log Settings"; | ||||
|     NSString *body = @"In iOS 10 and up, ASL has been replaced by os_log. " | ||||
|     "The os_log API is much more limited. Below, you can opt-into the old behavior " | ||||
|     "if you want cleaner, more reliable logs within FLEX, but this will break " | ||||
|     "anything that expects os_log to be working, such as Console.app. " | ||||
|     "This setting requires the app to restart to take effect. \n\n" | ||||
|  | ||||
|     "To get as close to the old behavior as possible with os_log enabled, logs must " | ||||
|     "be collected manually at launch and stored. This setting has no effect " | ||||
|     "on iOS 9 and below, or if os_log is disabled. " | ||||
|     "You should only enable persistent logging when you need it."; | ||||
|  | ||||
|     FLEXOSLogController *logController = (FLEXOSLogController *)self.logController; | ||||
|  | ||||
|     [FLEXAlert makeAlert:^(FLEXAlert *make) { | ||||
|         make.title(title).message(body); | ||||
|         make.button(aslToggle).destructiveStyle().handler(^(NSArray<NSString *> *strings) { | ||||
|             [defaults flex_toggleBoolForKey:kFLEXDefaultsDisableOSLogForceASLKey]; | ||||
|         }); | ||||
|  | ||||
|         make.button(persistence).handler(^(NSArray<NSString *> *strings) { | ||||
|             [defaults flex_toggleBoolForKey:kFLEXDefaultsiOSPersistentOSLogKey]; | ||||
|             logController.persistent = !persistent; | ||||
|             [logController.messages addObjectsFromArray:self.logMessages.list]; | ||||
|         }); | ||||
|         make.button(@"Dismiss").cancelStyle(); | ||||
|     } showFrom:self]; | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - FLEXGlobalsEntry | ||||
|  | ||||
| + (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row { | ||||
|     return @"⚠️  System Log"; | ||||
| } | ||||
|  | ||||
| + (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row { | ||||
|     return [self new]; | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - Table view data source | ||||
|  | ||||
| - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { | ||||
|     FLEXSystemLogMessage *logMessage = self.logMessages.filteredList[indexPath.row]; | ||||
|     return [FLEXSystemLogCell preferredHeightForLogMessage:logMessage inWidth:self.tableView.bounds.size.width]; | ||||
| } | ||||
|  | ||||
|  | ||||
| #pragma mark - Copy on long press | ||||
|  | ||||
| - (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath { | ||||
|     return YES; | ||||
| } | ||||
|  | ||||
| - (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { | ||||
|     return action == @selector(copy:); | ||||
| } | ||||
|  | ||||
| - (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { | ||||
|     if (action == @selector(copy:)) { | ||||
|         // We usually only want to copy the log message itself, not any metadata associated with it. | ||||
|         UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @""; | ||||
|     } | ||||
| } | ||||
|  | ||||
| - (UIContextMenuConfiguration *)tableView:(UITableView *)tableView | ||||
| contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath | ||||
|                                     point:(CGPoint)point __IOS_AVAILABLE(13.0) { | ||||
|     weakify(self) | ||||
|     return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil | ||||
|         actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) { | ||||
|             UIAction *copy = [UIAction actionWithTitle:@"Copy" | ||||
|                                                  image:nil | ||||
|                                             identifier:@"Copy" | ||||
|                                                handler:^(UIAction *action) { strongify(self) | ||||
|                 // We usually only want to copy the log message itself, not any metadata associated with it. | ||||
|                 UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @""; | ||||
|             }]; | ||||
|             return [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[copy]]; | ||||
|         } | ||||
|     ]; | ||||
| } | ||||
|  | ||||
| @end | ||||
							
								
								
									
										276
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/LLVM_LICENSE.TXT
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								Tweaks/FLEX/GlobalStateExplorers/SystemLog/LLVM_LICENSE.TXT
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,276 @@ | ||||
| ============================================================================== | ||||
| The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: | ||||
| ============================================================================== | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|     TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|     1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|     2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|     3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|     4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|     5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|     6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|     7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|     8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|     9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|     END OF TERMS AND CONDITIONS | ||||
|  | ||||
|     APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|     Copyright [yyyy] [name of copyright owner] | ||||
|  | ||||
|     Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|     you may not use this file except in compliance with the License. | ||||
|     You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|     Unless required by applicable law or agreed to in writing, software | ||||
|     distributed under the License is distributed on an "AS IS" BASIS, | ||||
|     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|     See the License for the specific language governing permissions and | ||||
|     limitations under the License. | ||||
|  | ||||
|  | ||||
| ---- LLVM Exceptions to the Apache 2.0 License ---- | ||||
|  | ||||
| As an exception, if, as a result of your compiling your source code, portions | ||||
| of this Software are embedded into an Object form of such source code, you | ||||
| may redistribute such embedded portions in such Object form without complying | ||||
| with the conditions of Sections 4(a), 4(b) and 4(d) of the License. | ||||
|  | ||||
| In addition, if you combine or link compiled forms of this Software with | ||||
| software that is licensed under the GPLv2 ("Combined Software") and if a | ||||
| court of competent jurisdiction determines that the patent provision (Section | ||||
| 3), the indemnity provision (Section 9) or other Section of the License | ||||
| conflicts with the conditions of the GPLv2, you may retroactively and | ||||
| prospectively choose to deem waived or otherwise exclude such Section(s) of | ||||
| the License, but only in their entirety and only with respect to the Combined | ||||
| Software. | ||||
|  | ||||
| ============================================================================== | ||||
| Software from third parties included in the LLVM Project: | ||||
| ============================================================================== | ||||
| The LLVM Project contains third party software which is under different license | ||||
| terms. All such code will be identified clearly using at least one of two | ||||
| mechanisms: | ||||
| 1) It will be in a separate directory tree with its own `LICENSE.txt` or | ||||
|    `LICENSE` file at the top containing the specific license and restrictions | ||||
|    which apply to that software, or | ||||
| 2) It will contain specific license and restriction terms at the top of every | ||||
|    file. | ||||
|  | ||||
| ============================================================================== | ||||
| Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): | ||||
| ============================================================================== | ||||
| University of Illinois/NCSA | ||||
| Open Source License | ||||
|  | ||||
| Copyright (c) 2010 Apple Inc. | ||||
| All rights reserved. | ||||
|  | ||||
| Developed by: | ||||
|  | ||||
|     LLDB Team | ||||
|  | ||||
|     http://lldb.llvm.org/ | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal with | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||||
| of the Software, and to permit persons to whom the Software is furnished to do | ||||
| so, subject to the following conditions: | ||||
|  | ||||
|     * Redistributions of source code must retain the above copyright notice, | ||||
|       this list of conditions and the following disclaimers. | ||||
|  | ||||
|     * Redistributions in binary form must reproduce the above copyright notice, | ||||
|       this list of conditions and the following disclaimers in the | ||||
|       documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     * Neither the names of the LLDB Team, copyright holders, nor the names of  | ||||
|       its contributors may be used to endorse or promote products derived from  | ||||
|       this Software without specific prior written permission. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | ||||
| CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE | ||||
| SOFTWARE. | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Balackburn
					Balackburn