| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "native_client/src/trusted/plugin/json_manifest.h" | 9 #include "native_client/src/trusted/plugin/json_manifest.h" |
| 10 | 10 |
| 11 #include <stdlib.h> | 11 #include <stdlib.h> |
| 12 | 12 |
| 13 #include "native_client/src/include/nacl_base.h" | 13 #include "native_client/src/include/nacl_base.h" |
| 14 #include "native_client/src/include/nacl_macros.h" | 14 #include "native_client/src/include/nacl_macros.h" |
| 15 #include "native_client/src/include/nacl_string.h" | 15 #include "native_client/src/include/nacl_string.h" |
| 16 #include "native_client/src/include/portability.h" | 16 #include "native_client/src/include/portability.h" |
| 17 #include "native_client/src/shared/platform/nacl_check.h" | 17 #include "native_client/src/shared/platform/nacl_check.h" |
| 18 #include "native_client/src/trusted/plugin/plugin_error.h" | 18 #include "native_client/src/trusted/plugin/plugin_error.h" |
| 19 #include "native_client/src/trusted/plugin/pnacl_options.h" |
| 19 #include "native_client/src/trusted/plugin/utility.h" | 20 #include "native_client/src/trusted/plugin/utility.h" |
| 20 #include "ppapi/cpp/dev/url_util_dev.h" | 21 #include "ppapi/cpp/dev/url_util_dev.h" |
| 21 #include "ppapi/cpp/var.h" | 22 #include "ppapi/cpp/var.h" |
| 22 #include "third_party/jsoncpp/source/include/json/reader.h" | 23 #include "third_party/jsoncpp/source/include/json/reader.h" |
| 23 | 24 |
| 24 namespace plugin { | 25 namespace plugin { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 // Top-level section name keys | 28 // Top-level section name keys |
| 28 const char* const kProgramKey = "program"; | 29 const char* const kProgramKey = "program"; |
| 29 const char* const kInterpreterKey = "interpreter"; | 30 const char* const kInterpreterKey = "interpreter"; |
| 30 const char* const kFilesKey = "files"; | 31 const char* const kFilesKey = "files"; |
| 31 | 32 |
| 32 // ISA Dictionary keys | 33 // ISA Dictionary keys |
| 33 const char* const kX8632Key = "x86-32"; | 34 const char* const kX8632Key = "x86-32"; |
| 34 const char* const kX8664Key = "x86-64"; | 35 const char* const kX8664Key = "x86-64"; |
| 35 const char* const kArmKey = "arm"; | 36 const char* const kArmKey = "arm"; |
| 36 const char* const kPortableKey = "portable"; | 37 const char* const kPortableKey = "portable"; |
| 37 | 38 |
| 38 // Url Resolution keys | 39 // Url Resolution keys |
| 39 const char* const kPnaclTranslateKey = "pnacl-translate"; | 40 const char* const kPnaclTranslateKey = "pnacl-translate"; |
| 40 const char* const kUrlKey = "url"; | 41 const char* const kUrlKey = "url"; |
| 41 | 42 |
| 42 // Cache support keys | 43 // Pnacl keys |
| 43 const char* const kCacheIdentityKey = "sha256"; | 44 const char* const kCacheIdentityKey = "sha256"; |
| 45 const char* const kOptLevelKey = "-O"; |
| 46 const char* const kPnaclExperimentalFlags = "experimental_flags"; |
| 44 | 47 |
| 45 // Sample manifest file: | 48 // Sample manifest file: |
| 46 // { | 49 // { |
| 47 // "program": { | 50 // "program": { |
| 48 // "x86-32": {"url": "myprogram_x86-32.nexe"}, | 51 // "x86-32": {"url": "myprogram_x86-32.nexe"}, |
| 49 // "x86-64": {"url": "myprogram_x86-64.nexe"}, | 52 // "x86-64": {"url": "myprogram_x86-64.nexe"}, |
| 50 // "arm": {"url": "myprogram_arm.nexe"}, | 53 // "arm": {"url": "myprogram_arm.nexe"}, |
| 51 // "portable": { | 54 // "portable": { |
| 52 // "pnacl-translate": { | 55 // "pnacl-translate": { |
| 53 // "url": "myprogram.pexe", | 56 // "url": "myprogram.pexe", |
| 54 // "sha256": "..." | 57 // "sha256": "...", |
| 58 // "-O": 0 |
| 55 // } | 59 // } |
| 56 // } | 60 // } |
| 57 // }, | 61 // }, |
| 58 // "interpreter": { | 62 // "interpreter": { |
| 59 // "x86-32": {"url": "interpreter_x86-32.nexe"}, | 63 // "x86-32": {"url": "interpreter_x86-32.nexe"}, |
| 60 // "x86-64": {"url": "interpreter_x86-64.nexe"}, | 64 // "x86-64": {"url": "interpreter_x86-64.nexe"}, |
| 61 // "arm": {"url": "interpreter_arm.nexe"} | 65 // "arm": {"url": "interpreter_arm.nexe"} |
| 62 // }, | 66 // }, |
| 63 // "files": { | 67 // "files": { |
| 64 // "foo.txt": { | 68 // "foo.txt": { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 return false; | 251 return false; |
| 248 } | 252 } |
| 249 } | 253 } |
| 250 | 254 |
| 251 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include | 255 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include |
| 252 // micro-architectures that can resolve to multiple valid sandboxes. | 256 // micro-architectures that can resolve to multiple valid sandboxes. |
| 253 bool has_isa = dictionary.isMember(sandbox_isa); | 257 bool has_isa = dictionary.isMember(sandbox_isa); |
| 254 bool has_portable = dictionary.isMember(kPortableKey); | 258 bool has_portable = dictionary.isMember(kPortableKey); |
| 255 | 259 |
| 256 if (!has_isa && !has_portable) { | 260 if (!has_isa && !has_portable) { |
| 257 error_info->SetReport(ERROR_MANIFEST_PROGRAM_MISSING_ARCH, | 261 error_info->SetReport( |
| 258 nacl::string("manifest: no version of ") + parent_key+ | 262 ERROR_MANIFEST_PROGRAM_MISSING_ARCH, |
| 263 nacl::string("manifest: no version of ") + parent_key + |
| 259 " given for current arch and no portable version found."); | 264 " given for current arch and no portable version found."); |
| 260 return false; | 265 return false; |
| 261 } | 266 } |
| 262 | 267 |
| 263 return true; | 268 return true; |
| 264 } | 269 } |
| 265 | 270 |
| 266 void GrabUrlAndCacheIdentity(const Json::Value& url_spec, | 271 void GrabUrlAndPnaclOptions(const Json::Value& url_spec, |
| 267 nacl::string* url, | 272 nacl::string* url, |
| 268 nacl::string* cache_identity) { | 273 PnaclOptions* pnacl_options) { |
| 269 *url = url_spec[kUrlKey].asString(); | 274 *url = url_spec[kUrlKey].asString(); |
| 270 if (url_spec.isMember(kCacheIdentityKey)) { | 275 if (url_spec.isMember(kCacheIdentityKey)) { |
| 271 *cache_identity = url_spec[kCacheIdentityKey].asString(); | 276 pnacl_options->set_bitcode_hash(url_spec[kCacheIdentityKey].asString()); |
| 277 } |
| 278 if (url_spec.isMember(kOptLevelKey)) { |
| 279 uint32_t opt_raw = url_spec[kOptLevelKey].asUInt(); |
| 280 // Clamp the opt value to fit into an int8_t. |
| 281 if (opt_raw > 3) |
| 282 opt_raw = 3; |
| 283 pnacl_options->set_opt_level(static_cast<int8_t>(opt_raw)); |
| 284 } |
| 285 if (url_spec.isMember(kPnaclExperimentalFlags)) { |
| 286 pnacl_options->set_experimental_flags( |
| 287 url_spec[kPnaclExperimentalFlags].asString()); |
| 272 } | 288 } |
| 273 } | 289 } |
| 274 | 290 |
| 275 bool GetURLFromISADictionary(const Json::Value& dictionary, | 291 bool GetURLFromISADictionary(const Json::Value& dictionary, |
| 276 const nacl::string& parent_key, | 292 const nacl::string& parent_key, |
| 277 const nacl::string& sandbox_isa, | 293 const nacl::string& sandbox_isa, |
| 278 bool prefer_portable, | 294 bool prefer_portable, |
| 279 nacl::string* url, | 295 nacl::string* url, |
| 280 nacl::string* cache_identity, | 296 PnaclOptions* pnacl_options, |
| 281 ErrorInfo* error_info, | 297 ErrorInfo* error_info) { |
| 282 bool* pnacl_translate) { | 298 if (url == NULL || pnacl_options == NULL || error_info == NULL) |
| 283 if (url == NULL || cache_identity == NULL || | |
| 284 error_info == NULL || pnacl_translate == NULL) | |
| 285 return false; | 299 return false; |
| 286 | 300 |
| 287 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) | 301 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) |
| 288 return false; | 302 return false; |
| 289 | 303 |
| 290 *url = ""; | 304 *url = ""; |
| 291 *cache_identity = ""; | |
| 292 *pnacl_translate = false; | |
| 293 | 305 |
| 294 // The call to IsValidISADictionary() above guarantees that either | 306 // The call to IsValidISADictionary() above guarantees that either |
| 295 // sandbox_isa or kPortableKey is present in the dictionary. | 307 // sandbox_isa or kPortableKey is present in the dictionary. |
| 296 bool has_portable = dictionary.isMember(kPortableKey); | 308 bool has_portable = dictionary.isMember(kPortableKey); |
| 297 bool has_isa = dictionary.isMember(sandbox_isa); | 309 bool has_isa = dictionary.isMember(sandbox_isa); |
| 298 nacl::string chosen_isa; | 310 nacl::string chosen_isa; |
| 299 if ((has_portable && prefer_portable) || !has_isa) { | 311 if ((has_portable && prefer_portable) || !has_isa) { |
| 300 chosen_isa = kPortableKey; | 312 chosen_isa = kPortableKey; |
| 301 } else { | 313 } else { |
| 302 chosen_isa = sandbox_isa; | 314 chosen_isa = sandbox_isa; |
| 303 } | 315 } |
| 304 const Json::Value& isa_spec = dictionary[chosen_isa]; | 316 const Json::Value& isa_spec = dictionary[chosen_isa]; |
| 305 // Check if this requires a pnacl-translate, otherwise just grab the URL. | 317 // Check if this requires a pnacl-translate, otherwise just grab the URL. |
| 306 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. | 318 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. |
| 307 if (isa_spec.isMember(kPnaclTranslateKey)) { | 319 if (isa_spec.isMember(kPnaclTranslateKey)) { |
| 308 GrabUrlAndCacheIdentity(isa_spec[kPnaclTranslateKey], url, cache_identity); | 320 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); |
| 309 *pnacl_translate = true; | 321 pnacl_options->set_translate(true); |
| 310 } else { | 322 } else { |
| 311 GrabUrlAndCacheIdentity(isa_spec, url, cache_identity); | 323 *url = isa_spec[kUrlKey].asString(); |
| 312 *pnacl_translate = false; | 324 pnacl_options->set_translate(false); |
| 313 } | 325 } |
| 314 | 326 |
| 315 return true; | 327 return true; |
| 316 } | 328 } |
| 317 | 329 |
| 318 bool GetKeyUrl(const Json::Value& dictionary, | 330 bool GetKeyUrl(const Json::Value& dictionary, |
| 319 const nacl::string& key, | 331 const nacl::string& key, |
| 320 const nacl::string& sandbox_isa, | 332 const nacl::string& sandbox_isa, |
| 321 const Manifest* manifest, | 333 const Manifest* manifest, |
| 322 bool prefer_portable, | 334 bool prefer_portable, |
| 323 nacl::string* full_url, | 335 nacl::string* full_url, |
| 324 nacl::string* cache_identity, | 336 PnaclOptions* pnacl_options, |
| 325 ErrorInfo* error_info, | 337 ErrorInfo* error_info) { |
| 326 bool* pnacl_translate) { | |
| 327 CHECK(full_url != NULL && error_info != NULL); | 338 CHECK(full_url != NULL && error_info != NULL); |
| 328 if (!dictionary.isMember(key)) { | 339 if (!dictionary.isMember(key)) { |
| 329 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 340 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 330 "file key not found in manifest"); | 341 "file key not found in manifest"); |
| 331 return false; | 342 return false; |
| 332 } | 343 } |
| 333 const Json::Value& isa_dict = dictionary[key]; | 344 const Json::Value& isa_dict = dictionary[key]; |
| 334 nacl::string relative_url; | 345 nacl::string relative_url; |
| 335 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable, | 346 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable, |
| 336 &relative_url, cache_identity, | 347 &relative_url, pnacl_options, error_info)) { |
| 337 error_info, pnacl_translate)) { | |
| 338 return false; | 348 return false; |
| 339 } | 349 } |
| 340 return manifest->ResolveURL(relative_url, full_url, error_info); | 350 return manifest->ResolveURL(relative_url, full_url, error_info); |
| 341 } | 351 } |
| 342 | 352 |
| 343 } // namespace | 353 } // namespace |
| 344 | 354 |
| 345 bool JsonManifest::Init(const nacl::string& manifest_json, | 355 bool JsonManifest::Init(const nacl::string& manifest_json, |
| 346 ErrorInfo* error_info) { | 356 ErrorInfo* error_info) { |
| 347 if (error_info == NULL) { | 357 if (error_info == NULL) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 "could not resolve url '" + relative_url + | 458 "could not resolve url '" + relative_url + |
| 449 "' relative to manifest base url '" + manifest_base_url_.c_str() + | 459 "' relative to manifest base url '" + manifest_base_url_.c_str() + |
| 450 "'."); | 460 "'."); |
| 451 return false; | 461 return false; |
| 452 } | 462 } |
| 453 *full_url = resolved_url.AsString(); | 463 *full_url = resolved_url.AsString(); |
| 454 return true; | 464 return true; |
| 455 } | 465 } |
| 456 | 466 |
| 457 bool JsonManifest::GetProgramURL(nacl::string* full_url, | 467 bool JsonManifest::GetProgramURL(nacl::string* full_url, |
| 458 nacl::string* cache_identity, | 468 PnaclOptions* pnacl_options, |
| 459 ErrorInfo* error_info, | 469 ErrorInfo* error_info) const { |
| 460 bool* pnacl_translate) const { | 470 if (full_url == NULL || pnacl_options == NULL || error_info == NULL) |
| 461 if (full_url == NULL || cache_identity == NULL || | |
| 462 error_info == NULL || pnacl_translate == NULL) | |
| 463 return false; | 471 return false; |
| 464 | 472 |
| 465 Json::Value program = dictionary_[kProgramKey]; | 473 Json::Value program = dictionary_[kProgramKey]; |
| 466 | 474 |
| 467 nacl::string nexe_url; | 475 nacl::string nexe_url; |
| 468 nacl::string error_string; | 476 nacl::string error_string; |
| 469 | 477 |
| 470 if (!GetURLFromISADictionary(program, | 478 if (!GetURLFromISADictionary(program, |
| 471 kProgramKey, | 479 kProgramKey, |
| 472 sandbox_isa_, | 480 sandbox_isa_, |
| 473 prefer_portable_, | 481 prefer_portable_, |
| 474 &nexe_url, | 482 &nexe_url, |
| 475 cache_identity, | 483 pnacl_options, |
| 476 error_info, | 484 error_info)) { |
| 477 pnacl_translate)) { | |
| 478 return false; | 485 return false; |
| 479 } | 486 } |
| 480 | 487 |
| 481 return ResolveURL(nexe_url, full_url, error_info); | 488 return ResolveURL(nexe_url, full_url, error_info); |
| 482 } | 489 } |
| 483 | 490 |
| 484 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { | 491 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { |
| 485 if (!dictionary_.isMember(kFilesKey)) { | 492 if (!dictionary_.isMember(kFilesKey)) { |
| 486 // trivial success: no keys when there is no "files" section. | 493 // trivial success: no keys when there is no "files" section. |
| 487 return true; | 494 return true; |
| 488 } | 495 } |
| 489 const Json::Value& files = dictionary_[kFilesKey]; | 496 const Json::Value& files = dictionary_[kFilesKey]; |
| 490 CHECK(files.isObject()); | 497 CHECK(files.isObject()); |
| 491 Json::Value::Members members = files.getMemberNames(); | 498 Json::Value::Members members = files.getMemberNames(); |
| 492 for (size_t i = 0; i < members.size(); ++i) { | 499 for (size_t i = 0; i < members.size(); ++i) { |
| 493 keys->insert(members[i]); | 500 keys->insert(members[i]); |
| 494 } | 501 } |
| 495 return true; | 502 return true; |
| 496 } | 503 } |
| 497 | 504 |
| 498 bool JsonManifest::ResolveKey(const nacl::string& key, | 505 bool JsonManifest::ResolveKey(const nacl::string& key, |
| 499 nacl::string* full_url, | 506 nacl::string* full_url, |
| 500 nacl::string* cache_identity, | 507 PnaclOptions* pnacl_options, |
| 501 ErrorInfo* error_info, | 508 ErrorInfo* error_info) const { |
| 502 bool* pnacl_translate) const { | |
| 503 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); | 509 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); |
| 504 // key must be one of kProgramKey or kFileKey '/' file-section-key | 510 // key must be one of kProgramKey or kFileKey '/' file-section-key |
| 505 | 511 |
| 506 if (full_url == NULL || cache_identity == NULL || | 512 if (full_url == NULL || pnacl_options == NULL || error_info == NULL) |
| 507 error_info == NULL || pnacl_translate == NULL) | |
| 508 return false; | 513 return false; |
| 509 | 514 |
| 510 if (key == kProgramKey) { | 515 if (key == kProgramKey) { |
| 511 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_, | 516 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_, |
| 512 full_url, cache_identity, error_info, pnacl_translate); | 517 full_url, pnacl_options, error_info); |
| 513 } | 518 } |
| 514 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); | 519 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); |
| 515 if (p == key.end()) { | 520 if (p == key.end()) { |
| 516 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 521 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 517 nacl::string("ResolveKey: invalid key, no slash: ") | 522 nacl::string("ResolveKey: invalid key, no slash: ") |
| 518 + key); | 523 + key); |
| 519 return false; | 524 return false; |
| 520 } | 525 } |
| 521 | 526 |
| 522 // generalize to permit other sections? | 527 // generalize to permit other sections? |
| (...skipping 14 matching lines...) Expand all Loading... |
| 537 nacl::string("ResolveKey: no \"files\" dictionary")); | 542 nacl::string("ResolveKey: no \"files\" dictionary")); |
| 538 return false; | 543 return false; |
| 539 } | 544 } |
| 540 if (!files.isMember(rest)) { | 545 if (!files.isMember(rest)) { |
| 541 error_info->SetReport( | 546 error_info->SetReport( |
| 542 ERROR_MANIFEST_RESOLVE_URL, | 547 ERROR_MANIFEST_RESOLVE_URL, |
| 543 nacl::string("ResolveKey: no such \"files\" entry: ") + key); | 548 nacl::string("ResolveKey: no such \"files\" entry: ") + key); |
| 544 return false; | 549 return false; |
| 545 } | 550 } |
| 546 return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_, | 551 return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_, |
| 547 full_url, cache_identity, error_info, pnacl_translate); | 552 full_url, pnacl_options, error_info); |
| 548 } | 553 } |
| 549 | 554 |
| 550 } // namespace plugin | 555 } // namespace plugin |
| OLD | NEW |