1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using NUnit.Framework; 9 using Antmicro.Renode.Core; 10 using System.Collections.Generic; 11 12 using System.Linq; 13 14 namespace Antmicro.Renode.UnitTests.SymbolLookupTests 15 { 16 [TestFixture] 17 public class ElfMergeTests 18 { 19 [Test] ShouldMergeTrimEndAndBeginning()20 public void ShouldMergeTrimEndAndBeginning() 21 { 22 var symbols1 = new List<Symbol> 23 { 24 new Symbol(0, 50, "一"), 25 new Symbol(50, 100, "三"), 26 }; 27 var symbols2 = new List<Symbol> 28 { 29 new Symbol(30, 70, "二"), 30 }; 31 var expectedSymbols = new List<Symbol> 32 { 33 new Symbol(0, 30, "一"), 34 new Symbol(30, 70, "二"), 35 new Symbol(70, 100, "三"), 36 }; 37 var addressesToQuery = new List<uint>{25, 35, 75}; 38 var lookup = new SymbolLookup(); 39 lookup.InsertSymbols(symbols1); 40 lookup.InsertSymbols(symbols2); 41 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 42 } 43 44 [Test] ShouldSortedIntervalsHaveExpectedLayout()45 public void ShouldSortedIntervalsHaveExpectedLayout() 46 { 47 var symbols1 = new List<Symbol> 48 { 49 new Symbol(0, 100, "一"), 50 new Symbol(1, 85, "四"), 51 new Symbol(2, 70, "国"), 52 new Symbol(80, 85, "猫"), 53 new Symbol(3, 60, "中"), 54 new Symbol(70, 75, "私"), 55 new Symbol(4, 15, "五"), 56 new Symbol(20, 35, "三"), 57 }; 58 var symbols2 = new List<Symbol> 59 { 60 new Symbol(5, 25, "糞"), 61 new Symbol(40, 82, "二"), 62 new Symbol(50, 55, "ICantSpeekJapaneese"), 63 new Symbol(45, 50, "ICantSpeekKorean"), 64 }; 65 var expectedSymbols = new List<Symbol> 66 { 67 new Symbol(0, 5, "一"), 68 new Symbol(1, 5, "四"), 69 new Symbol(2, 5, "国"), 70 new Symbol(3, 5, "中"), 71 new Symbol(4, 5, "五"), 72 new Symbol(5, 25, "糞"), 73 new Symbol(25, 40, "中"), 74 new Symbol(25, 35, "三"), 75 new Symbol(40, 82, "二"), 76 new Symbol(45, 50, "ICantSpeekKorean"), 77 new Symbol(50, 55, "ICantSpeekJapaneese"), 78 new Symbol(82, 100, "一"), 79 new Symbol(82, 85, "猫"), 80 }; 81 var addressesToQuery = new List<uint>{0, 1, 2, 3, 4, 10, 37, 30, 42, 47, 53, 90, 83}; 82 var lookup = new SymbolLookup(); 83 lookup.InsertSymbols(symbols1); 84 lookup.InsertSymbols(symbols2); 85 CollectionAssert.AreEqual( 86 expectedSymbols, 87 addressesToQuery.Select(address => lookup.GetSymbolByAddress(address)) 88 ); 89 } 90 91 [Test] ShouldTrimEndAndBeginning2()92 public void ShouldTrimEndAndBeginning2() 93 { 94 var symbols1 = new List<Symbol> 95 { 96 new Symbol(30, 70, "二"), 97 }; 98 var symbols2 = new List<Symbol> 99 { 100 new Symbol(0, 40, "一"), 101 new Symbol(60, 100, "三"), 102 }; 103 var expectedSymbols = new List<Symbol> 104 { 105 new Symbol(0, 40, "一"), 106 new Symbol(40, 60, "二"), 107 new Symbol(60, 100, "三"), 108 }; 109 var addressesToQuery = new List<uint>{25, 59, 60}; 110 var lookup = new SymbolLookup(); 111 lookup.InsertSymbols(symbols1); 112 lookup.InsertSymbols(symbols2); 113 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 114 115 } 116 117 [Test] ShouldTrimCakeEnds()118 public void ShouldTrimCakeEnds() 119 { 120 var symbols1 = new List<Symbol> 121 { 122 new Symbol(0, 100, "一"), 123 new Symbol(1, 85, "四"), 124 new Symbol(2, 70, "国"), 125 new Symbol(3, 60, "中"), 126 new Symbol(4, 60, "五"), 127 new Symbol(20, 50, "三"), 128 }; 129 var symbols2 = new List<Symbol> 130 { 131 new Symbol(50, 100, "猫"), 132 }; 133 var expectedSymbols = new List<Symbol> 134 { 135 new Symbol(0, 50, "一"), 136 new Symbol(1, 50, "四"), 137 new Symbol(2, 50, "国"), 138 new Symbol(3, 50, "中"), 139 new Symbol(4, 50, "五"), 140 new Symbol(20, 50, "三"), 141 new Symbol(50, 100, "猫"), 142 }; 143 var addressesToQuery = new List<uint>{0, 1, 2, 3, 15, 35, 99}; 144 var lookup = new SymbolLookup(); 145 lookup.InsertSymbols(symbols1); 146 lookup.InsertSymbols(symbols2); 147 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 148 } 149 150 [Test] ShouldTrimCakeBeginnings()151 public void ShouldTrimCakeBeginnings() 152 { 153 var symbols1 = new List<Symbol> 154 { 155 new Symbol(0, 100, "一"), 156 new Symbol(1, 85, "四"), 157 new Symbol(2, 70, "国"), 158 new Symbol(3, 60, "中"), 159 new Symbol(20, 50, "三"), 160 }; 161 var symbols2 = new List<Symbol> 162 { 163 new Symbol(0, 30, "猫"), 164 }; 165 var expectedSymbols = new List<Symbol> { 166 new Symbol(0, 30, "猫"), 167 new Symbol(30, 100, "一"), 168 new Symbol(30, 85, "四"), 169 new Symbol(30, 70, "国"), 170 new Symbol(30, 60, "中"), 171 new Symbol(30, 50, "三"), 172 }; 173 var addressesToQuery = new List<uint>{10, 95, 80, 65, 55, 45}; 174 var lookup = new SymbolLookup(); 175 lookup.InsertSymbols(symbols1); 176 lookup.InsertSymbols(symbols2); 177 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 178 } 179 180 [Test] ShouldCutIntoCake()181 public void ShouldCutIntoCake() 182 { 183 var symbols1 = new List<Symbol> 184 { 185 new Symbol(0, 100, "一"), 186 new Symbol(1, 85, "四"), 187 new Symbol(2, 70, "国"), 188 new Symbol(3, 60, "中"), 189 new Symbol(20, 50, "三"), 190 }; 191 var symbols2 = new List<Symbol> 192 { 193 new Symbol(35, 40, "猫"), 194 }; 195 var expectedSymbols = new List<Symbol> { 196 new Symbol(0, 35, "一"), 197 new Symbol(1, 35, "四"), 198 new Symbol(2, 35, "国"), 199 new Symbol(3, 35, "中"), 200 new Symbol(20, 35, "三"), 201 new Symbol(35, 40, "猫"), 202 new Symbol(40, 100, "一"), 203 new Symbol(40, 85, "四"), 204 new Symbol(40, 70, "国"), 205 new Symbol(40, 60, "中"), 206 new Symbol(40, 50, "三"), 207 }; 208 var addressesToQuery = new List<uint>{0, 1, 2, 10, 25, 37, 90, 80, 65, 55, 45}; 209 var lookup = new SymbolLookup(); 210 lookup.InsertSymbols(symbols1); 211 lookup.InsertSymbols(symbols2); 212 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 213 } 214 215 [Test] ShouldTrimCakeToTopSymbol()216 public void ShouldTrimCakeToTopSymbol() 217 { 218 var symbols1 = new List<Symbol> 219 { 220 new Symbol(0, 100, "一"), 221 new Symbol(1, 85, "四"), 222 new Symbol(2, 70, "国"), 223 new Symbol(3, 60, "中"), 224 new Symbol(4, 60, "五"), 225 new Symbol(20, 50, "三"), 226 }; 227 var symbols2 = new List<Symbol> 228 { 229 new Symbol(0, 30, "猫"), 230 new Symbol(40, 100, "糞"), 231 }; 232 var expectedSymbols = new List<Symbol> { 233 new Symbol(0, 30, "猫"), 234 new Symbol(30, 40, "三"), 235 new Symbol(40, 100, "糞"), 236 }; 237 var addressesToQuery = new List<uint>{10, 37, 80}; 238 var lookup = new SymbolLookup(); 239 lookup.InsertSymbols(symbols1); 240 lookup.InsertSymbols(symbols2); 241 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 242 } 243 244 [Test] ShouldTrimAndOvershadow()245 public void ShouldTrimAndOvershadow() 246 { 247 var symbols1 = new List<Symbol> 248 { 249 new Symbol(0, 10, "一"), 250 new Symbol(1, 8, "四"), 251 new Symbol(20, 40, "国"), 252 new Symbol(30, 40, "中"), 253 new Symbol(40, 60, "五"), 254 new Symbol(45, 55, "三"), 255 }; 256 var symbols2 = new List<Symbol> 257 { 258 new Symbol(5, 50, "猫"), 259 new Symbol(10, 15, "糞"), 260 }; 261 var expectedSymbols = new List<Symbol> { 262 new Symbol(0, 5, "一"), 263 new Symbol(1, 5, "四"), 264 new Symbol(5, 50, "猫"), 265 new Symbol(10, 15, "糞"), 266 new Symbol(50, 60, "五"), 267 new Symbol(50, 55, "三"), 268 }; 269 var addressesToQuery = new List<uint>{0, 1, 45, 12, 59, 52}; 270 var lookup = new SymbolLookup(); 271 lookup.InsertSymbols(symbols1); 272 lookup.InsertSymbols(symbols2); 273 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 274 } 275 276 [Test] ShouldSplitCake()277 public void ShouldSplitCake() 278 { 279 var symbols1 = new List<Symbol> 280 { 281 new Symbol(0, 5, "一"), 282 new Symbol(1, 4, "四"), 283 }; 284 var symbols2 = new List<Symbol> 285 { 286 new Symbol(2, 2, "猫"), 287 }; 288 var expectedSymbols = new List<Symbol> { 289 new Symbol(0, 2, "一"), 290 new Symbol(1, 2, "四"), 291 new Symbol(2, 2, "猫"), 292 new Symbol(2, 4, "四"), 293 new Symbol(2, 5, "一"), 294 }; 295 var addressesToQuery = new List<uint>{0, 1, 2, 3, 4}; 296 var lookup = new SymbolLookup(); 297 lookup.InsertSymbols(symbols1); 298 lookup.InsertSymbols(symbols2); 299 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 300 } 301 302 [Test] ShouldTrimAndOverShadowOnABase()303 public void ShouldTrimAndOverShadowOnABase() 304 { 305 var symbols1 = new List<Symbol> 306 { 307 new Symbol(0, 100, "一"), 308 new Symbol(1, 8, "四"), 309 new Symbol(20, 40, "国"), 310 new Symbol(30, 40, "中"), 311 new Symbol(40, 60, "五"), 312 new Symbol(45, 55, "三"), 313 }; 314 var symbols2 = new List<Symbol> 315 { 316 new Symbol(5, 50, "猫"), 317 new Symbol(10, 15, "糞"), 318 }; 319 var expectedSymbols = new List<Symbol> { 320 new Symbol(0, 5, "一"), 321 new Symbol(1, 5, "四"), 322 new Symbol(5, 50, "猫"), 323 new Symbol(10, 15, "糞"), 324 new Symbol(50, 100, "一"), 325 new Symbol(50, 60, "五"), 326 new Symbol(50, 55, "三"), 327 }; 328 var addressesToQuery = new List<uint>{0, 3, 5, 14, 60, 59, 51}; 329 var lookup = new SymbolLookup(); 330 lookup.InsertSymbols(symbols1); 331 lookup.InsertSymbols(symbols2); 332 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 333 } 334 335 [Test] ShouldSplitCakeAfterSecondTower()336 public void ShouldSplitCakeAfterSecondTower() 337 { 338 var symbols1 = new List<Symbol> 339 { 340 new Symbol(0, 100, "一"), 341 new Symbol(1, 8, "四"), 342 new Symbol(20, 40, "国"), 343 new Symbol(30, 40, "中"), 344 new Symbol(50, 60, "五"), 345 new Symbol(50, 55, "三"), 346 }; 347 var symbols2 = new List<Symbol> 348 { 349 new Symbol(42, 47, "猫"), 350 new Symbol(43, 43, "糞"), 351 }; 352 var expectedSymbols = new List<Symbol> { 353 new Symbol(0, 42, "一"), 354 new Symbol(1, 8, "四"), 355 new Symbol(20, 40, "国"), 356 new Symbol(30, 40, "中"), 357 new Symbol(42, 47, "猫"), 358 new Symbol(43, 43, "糞"), 359 new Symbol(47, 100, "一"), 360 new Symbol(50, 60, "五"), 361 new Symbol(50, 55, "三"), 362 }; 363 var addressesToQuery = new List<uint>{41, 5, 25, 35, 45, 43, 48, 58, 50}; 364 var lookup = new SymbolLookup(); 365 lookup.InsertSymbols(symbols1); 366 lookup.InsertSymbols(symbols2); 367 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 368 } 369 370 [Test] ShouldHaveSlicedSymbolInNameLookup()371 public void ShouldHaveSlicedSymbolInNameLookup() 372 { 373 var symbols1 = new List<Symbol> 374 { 375 new Symbol(20, 40, "国"), 376 new Symbol(30, 40, "中"), 377 new Symbol(50, 60, "五"), 378 new Symbol(50, 55, "三"), 379 }; 380 var symbols2 = new List<Symbol> 381 { 382 new Symbol(30, 35, "中"), 383 }; 384 var expectedSymbols = new List<Symbol> { 385 new Symbol(20, 30, "国"), 386 new Symbol(30, 35, "中"), 387 new Symbol(35, 40, "中"), 388 new Symbol(50, 60, "五"), 389 new Symbol(50, 55, "三"), 390 }; 391 var addressesToQuery = new List<uint>{20, 30, 35, 58, 50}; 392 var lookup = new SymbolLookup(); 393 lookup.InsertSymbols(symbols1); 394 lookup.InsertSymbols(symbols2); 395 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 396 var name = expectedSymbols[1].Name; 397 Assert.AreEqual(expectedSymbols[1], lookup.GetSymbolsByName(name).ElementAt(0)); 398 Assert.AreEqual(expectedSymbols[2], lookup.GetSymbolsByName(name).ElementAt(1)); 399 } 400 401 [Test] ShouldPlaceZeroLenghtSymbolBeforeCake()402 public void ShouldPlaceZeroLenghtSymbolBeforeCake() 403 { 404 var symbols1 = new List<Symbol> 405 { 406 new Symbol(50, 100, "一"), 407 new Symbol(50, 75, "三"), 408 }; 409 var symbols2 = new List<Symbol> 410 { 411 new Symbol(50, 50, "二"), 412 }; 413 var expectedSymbols = new List<Symbol> 414 { 415 new Symbol(50, 100, "一"), 416 new Symbol(50, 75, "三"), 417 new Symbol(50, 50, "二"), 418 }; 419 var addressesToQuery = new List<uint>{90, 55, 50}; 420 var lookup = new SymbolLookup(); 421 lookup.InsertSymbols(symbols1); 422 lookup.InsertSymbols(symbols2); 423 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 424 } 425 426 [Test] ShouldCoverZeroLenghtSymbol()427 public void ShouldCoverZeroLenghtSymbol() 428 { 429 var symbols1 = new List<Symbol> 430 { 431 new Symbol(50, 50, "二"), 432 }; 433 var symbols2 = new List<Symbol> 434 { 435 new Symbol(50, 100, "一"), 436 new Symbol(50, 75, "三"), 437 }; 438 var expectedSymbols = new List<Symbol> 439 { 440 new Symbol(50, 100, "一"), 441 new Symbol(50, 75, "三"), 442 }; 443 var addressesToQuery = new List<uint>{90, 55}; 444 var lookup = new SymbolLookup(); 445 lookup.InsertSymbols(symbols1); 446 lookup.InsertSymbols(symbols2); 447 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 448 IReadOnlyCollection<Symbol> symbols; 449 Assert.IsFalse(lookup.TryGetSymbolsByName("二", out symbols), "Symbol \"二\"should not be present."); 450 } 451 452 [Test] ShouldZeroLenghtSymbolCutAfterCake()453 public void ShouldZeroLenghtSymbolCutAfterCake() 454 { 455 var symbols1 = new List<Symbol> 456 { 457 new Symbol(0, 50, "一"), 458 new Symbol(10, 50, "三"), 459 }; 460 var symbols2 = new List<Symbol> 461 { 462 new Symbol(50, 50, "二"), 463 }; 464 var expectedSymbols = new List<Symbol> 465 { 466 new Symbol(0, 50, "一"), 467 new Symbol(10, 50, "三"), 468 new Symbol(50, 50, "二"), 469 }; 470 var addressesToQuery = new List<uint>{0, 15, 50}; 471 var lookup = new SymbolLookup(); 472 lookup.InsertSymbols(symbols1); 473 lookup.InsertSymbols(symbols2); 474 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 475 } 476 477 [Test] ShouldNotDestroyOtherSymbolLookupCache()478 public void ShouldNotDestroyOtherSymbolLookupCache() 479 { 480 var symbols1 = new List<Symbol> 481 { 482 new Symbol(0, 100, "一"), 483 new Symbol(1, 85, "四"), 484 new Symbol(2, 70, "国"), 485 new Symbol(80, 85, "猫"), 486 new Symbol(3, 60, "中"), 487 new Symbol(70, 75, "私"), 488 new Symbol(4, 15, "五"), 489 new Symbol(20, 35, "三"), 490 }; 491 var symbols2 = new List<Symbol> 492 { 493 new Symbol(5, 25, "糞"), 494 new Symbol(40, 82, "二"), 495 new Symbol(50, 55, "ICantSpeekJapaneese"), 496 new Symbol(45, 50, "ICantSpeekKorean"), 497 }; 498 var mergedSymbols = new List<Symbol> 499 { 500 new Symbol(0, 5, "一"), 501 new Symbol(1, 5, "四"), 502 new Symbol(2, 5, "国"), 503 new Symbol(3, 5, "中"), 504 new Symbol(4, 5, "五"), 505 new Symbol(5, 25, "糞"), 506 new Symbol(25, 40, "中"), 507 new Symbol(25, 35, "三"), 508 new Symbol(40, 82, "二"), 509 new Symbol(45, 50, "ICantSpeekKorean"), 510 new Symbol(50, 55, "ICantSpeekJapaneese"), 511 new Symbol(82, 100, "一"), 512 new Symbol(82, 85, "猫"), 513 }; 514 var addressesToQuery = new List<uint>{0, 1, 2, 3, 4, 10, 37, 30, 42, 47, 53, 90, 83}; 515 var lookup = new List<SymbolLookup> {new SymbolLookup(), new SymbolLookup()}; 516 lookup[0].InsertSymbols(symbols1); 517 lookup[1].InsertSymbols(symbols1); 518 lookup[0].InsertSymbols(symbols2); 519 CollectionAssert.AreEqual( 520 mergedSymbols, 521 addressesToQuery.Select(address => lookup[0].GetSymbolByAddress(address)) 522 ); 523 CollectionAssert.AreEqual( 524 symbols1, 525 symbols1.Select(symbol => lookup[1].GetSymbolByAddress(symbol.Start)) 526 ); 527 } 528 529 /// <summary> 530 /// Regression test. "三" was removed and wasn't added. 531 /// </summary> 532 [Test] ShouldPerserveSymbol()533 public void ShouldPerserveSymbol() 534 { 535 var symbols1 = new List<Symbol> 536 { 537 new Symbol(0, 100, "一"), 538 new Symbol(20, 35, "三"), 539 new Symbol(100, 105, "猫"), 540 }; 541 var symbols2 = new List<Symbol> 542 { 543 new Symbol(15, 25, "私"), 544 }; 545 var lookup = new SymbolLookup(); 546 lookup.InsertSymbols(symbols1); 547 lookup.InsertSymbols(symbols2); 548 549 var symbol = symbols1[1]; 550 IReadOnlyCollection<Symbol> symbols; 551 Assert.IsTrue( 552 lookup.TryGetSymbolsByName(symbol.Name, out symbols), 553 string.Format("Symbol {0} has NOT been deduplicated.", symbol) 554 ); 555 } 556 557 /// <summary> 558 /// This is a regression test. Previously such inserts resulted in infinite loop. 559 /// </summary> 560 [Test] ShouldMergeOverlappingThumbSymbols()561 public void ShouldMergeOverlappingThumbSymbols() 562 { 563 var symbols1 = new List<Symbol> 564 { 565 new Symbol(10, 20, "一", ELFSharp.ELF.Sections.SymbolType.NotSpecified, ELFSharp.ELF.Sections.SymbolBinding.Global, true), 566 }; 567 var symbols2 = new List<Symbol> 568 { 569 new Symbol(5, 15, "悪魔", ELFSharp.ELF.Sections.SymbolType.NotSpecified, ELFSharp.ELF.Sections.SymbolBinding.Global, true), 570 }; 571 var lookup = new SymbolLookup(); 572 lookup.InsertSymbols(symbols1); 573 lookup.InsertSymbols(symbols2); 574 } 575 576 [Test] ShouldFavorUnempty()577 public void ShouldFavorUnempty() 578 { 579 var symbols = new List<Symbol> 580 { 581 new Symbol(0, 10, "Unempty"), 582 new Symbol(0, 10, ""), 583 new Symbol(10, 20, "Other"), 584 }; 585 586 var expectedSymbols = new List<Symbol> 587 { 588 new Symbol(0, 10, "Unempty"), 589 new Symbol(10, 20, "Other"), 590 }; 591 592 var addressesToQuery = new List<uint>{0, 10}; 593 var lookup = new SymbolLookup(); 594 lookup.InsertSymbols(symbols); 595 CollectionAssert.AreEqual(expectedSymbols, addressesToQuery.Select(address => lookup.GetSymbolByAddress(address))); 596 } 597 } 598 } 599