1 /* 2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #define IOKIT_ENABLE_SHARED_PTR 30 31 #include <IOKit/IOKernelReportStructs.h> 32 #include <IOKit/IOKernelReporters.h> 33 34 35 //#define IORDEBUG_LEGEND 1 36 37 #ifdef IORDEBUG_LEGEND 38 #define IORLEGENDLOG(fmt, args...) \ 39 do { \ 40 IOLog("IOReportLegend | "); \ 41 IOLog(fmt, ##args); \ 42 IOLog("\n"); \ 43 } while(0) 44 #else 45 #define IORLEGENDLOG(fmt, args...) 46 #endif 47 48 49 #define super OSObject 50 OSDefineMetaClassAndStructors(IOReportLegend, OSObject); 51 52 OSSharedPtr<IOReportLegend> 53 IOReportLegend::with(OSArray *legend) 54 { 55 OSSharedPtr<IOReportLegend> iorLegend = OSMakeShared<IOReportLegend>(); 56 57 if (iorLegend) { 58 if (legend != NULL) { 59 if (iorLegend->initWith(legend) != kIOReturnSuccess) { 60 return nullptr; 61 } 62 } 63 64 return iorLegend; 65 } else { 66 return nullptr; 67 } 68 } 69 70 /* must clean up everything if it fails */ 71 IOReturn 72 IOReportLegend::initWith(OSArray *legend) 73 { 74 if (legend) { 75 _reportLegend = OSArray::withArray(legend); 76 } 77 78 if (_reportLegend == NULL) { 79 return kIOReturnError; 80 } else { 81 return kIOReturnSuccess; 82 } 83 } 84 85 86 void 87 IOReportLegend::free(void) 88 { 89 super::free(); 90 } 91 92 93 OSArray* 94 IOReportLegend::getLegend(void) 95 { 96 return _reportLegend.get(); 97 } 98 99 IOReturn 100 IOReportLegend::addReporterLegend(IOService *reportingService, 101 IOReporter *reporter, 102 const char *groupName, 103 const char *subGroupName) 104 { 105 IOReturn res = kIOReturnError; 106 OSSharedPtr<IOReportLegend> legend; 107 OSSharedPtr<OSObject> curLegend; 108 109 // No need to check groupName and subGroupName because optional params 110 if (!reportingService || !reporter) { 111 goto finish; 112 } 113 114 // It's fine if the legend doesn't exist (IOReportLegend::with(NULL) 115 // is how you make an empty legend). If it's not an array, then 116 // we're just going to replace it. 117 curLegend = reportingService->copyProperty(kIOReportLegendKey); 118 legend = IOReportLegend::with(OSDynamicCast(OSArray, curLegend.get())); 119 if (!legend) { 120 goto finish; 121 } 122 123 // Add the reporter's entries and update the service property. 124 // The overwrite triggers a release of the old legend array. 125 legend->addReporterLegend(reporter, groupName, subGroupName); 126 reportingService->setProperty(kIOReportLegendKey, legend->getLegend()); 127 reportingService->setProperty(kIOReportLegendPublicKey, true); 128 129 res = kIOReturnSuccess; 130 131 finish: 132 return res; 133 } 134 135 136 IOReturn 137 IOReportLegend::addLegendEntry(IOReportLegendEntry *legendEntry, 138 const char *groupName, 139 const char *subGroupName) 140 { 141 kern_return_t res = kIOReturnError; 142 OSSharedPtr<const OSSymbol> tmpGroupName; 143 OSSharedPtr<const OSSymbol> tmpSubGroupName; 144 145 if (!legendEntry) { 146 return res; 147 } 148 149 if (groupName) { 150 tmpGroupName = OSSymbol::withCString(groupName); 151 } 152 153 if (subGroupName) { 154 tmpSubGroupName = OSSymbol::withCString(subGroupName); 155 } 156 157 // It is ok to call appendLegendWith() if tmpGroups are NULL 158 res = organizeLegend(legendEntry, tmpGroupName.get(), tmpSubGroupName.get()); 159 160 return res; 161 } 162 163 164 IOReturn 165 IOReportLegend::addReporterLegend(IOReporter *reporter, 166 const char *groupName, 167 const char *subGroupName) 168 { 169 IOReturn res = kIOReturnError; 170 OSSharedPtr<IOReportLegendEntry> legendEntry; 171 172 if (reporter) { 173 legendEntry = reporter->createLegend(); 174 175 if (legendEntry) { 176 res = addLegendEntry(legendEntry.get(), groupName, subGroupName); 177 } 178 } 179 180 return res; 181 } 182 183 184 IOReturn 185 IOReportLegend::organizeLegend(IOReportLegendEntry *legendEntry, 186 const OSSymbol *groupName, 187 const OSSymbol *subGroupName) 188 { 189 if (!legendEntry) { 190 return kIOReturnBadArgument; 191 } 192 193 if (!groupName && subGroupName) { 194 return kIOReturnBadArgument; 195 } 196 197 IORLEGENDLOG("IOReportLegend::organizeLegend"); 198 // Legend is empty, enter first node 199 if (_reportLegend == NULL) { 200 IORLEGENDLOG("IOReportLegend::new legend creation"); 201 _reportLegend = OSArray::withCapacity(1); 202 203 if (!_reportLegend) { 204 return kIOReturnNoMemory; 205 } 206 } 207 208 if (groupName) { 209 legendEntry->setObject(kIOReportLegendGroupNameKey, groupName); 210 } 211 212 if (subGroupName) { 213 legendEntry->setObject(kIOReportLegendSubGroupNameKey, subGroupName); 214 } 215 216 _reportLegend->setObject(legendEntry); 217 218 // callers can now safely release legendEntry (it is part of _reportLegend) 219 220 return kIOReturnSuccess; 221 } 222