找出引起異常的字符

大家可能都遇到過梯轻,一些比較特殊的字符,在排版的時候尽棕,或者在渲染的時候喳挑,會拋出異常。
當(dāng)我們調(diào)試的時候滔悉,加了異常斷點伊诵,就會觸發(fā)斷點。
這次主要是記錄一下回官,當(dāng)出現(xiàn)這種異常的時候曹宴,怎樣把引起這個異常的文字找出來。

我們先看一下出現(xiàn)這種異常時的堆棧信息

(lldb) bt
* thread #1: tid = 0x70ed65, 0x0000000118914c6b libc++abi.dylib`__cxa_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
    frame #0: 0x0000000118914c6b libc++abi.dylib`__cxa_throw
    frame #1: 0x00000001311c782f libType1Scaler.dylib`TType1LWFNMultipleMasterHFMXTable::TType1LWFNMultipleMasterHFMXTable(TFontObjectSurrogate const&, int, short, short, int*) + 121
    frame #2: 0x00000001311c7756 libType1Scaler.dylib`TType1LWFNFont::CreateHFMXTable() const + 86
    frame #3: 0x00000001311c76f5 libType1Scaler.dylib`TType1HFMXTableSurrogate::TType1HFMXTableSurrogate(TType1PSFont const&) + 31
    frame #4: 0x00000001311c6ec9 libType1Scaler.dylib`TType1PSFont::GetFontInstanceSpec(TType1Transform const&, FixedPoint&, FixedPoint&, FixedPoint&, FixedPoint&, FixedPoint&, FixedRectangle&, FontMetrics&) const + 647
    frame #5: 0x00000001311c6be4 libType1Scaler.dylib`TType1Strike::GetSpecs(StrikeSpecs&) const + 100
    frame #6: 0x00000001311bff2d libType1Scaler.dylib`Type1GetStrikeSpecs(unsigned int, TStrikeDescription const*, StrikeSpecs*) + 48
    frame #7: 0x000000011aba87a0 libFontParser.dylib`TConcreteFontScaler::GetFontInfo(FPFontInfo*) const + 48
    frame #8: 0x000000011ab80525 libFontParser.dylib`TFPFont::FillFontInfo(TFPFontInfo&) const + 203
    frame #9: 0x000000011ab80412 libFontParser.dylib`TFPFont::GetFontInfo() const + 46
    frame #10: 0x000000011ab803de libFontParser.dylib`FPFontIsMonospaced + 9
    frame #11: 0x0000000113bf63cd CoreGraphics`get_font_info + 244
    frame #12: 0x0000000113b84b47 CoreGraphics`get_font_info + 63
    frame #13: 0x0000000113b84af9 CoreGraphics`CGFontGetNumberOfGlyphs + 9
    frame #14: 0x00000001168131ed CoreText`TBaseFont::CopyGraphicsFont() const + 43
    frame #15: 0x0000000116863446 CoreText`TBaseFont::CopyTable(unsigned int) const + 188
    frame #16: 0x00000001168476fc CoreText`TBaseFont::GetCmapTable() const + 60
    frame #17: 0x000000011685d7a2 CoreText`TBaseFont::GetUnicodeEncoding() const + 58
    frame #18: 0x000000011685c367 CoreText`TBaseFont::GetUnicodeCmapSubHeader(void const**) const + 29
    frame #19: 0x000000011685c506 CoreText`TBaseFont::CopyCharacterSet() const + 206
    frame #20: 0x000000011680a2c2 CoreText`TBaseFont::GetCharacterSetInternal() const + 42
    frame #21: 0x0000000116808211 CoreText`CompareCharSet(__CFCharacterSet const*, TBaseFont const*) + 17
    frame #22: 0x000000011680ff1d CoreText`TDescriptorSource::CopyDescriptorsForRequestFromArray(__CFArray const*, __CFDictionary const*, CFComparisonResult (*)(void const*, void const*, void*), void*, unsigned long, bool) const + 1325
    frame #23: 0x000000011680e47e CoreText`TDescriptorSource::CopyDescriptorsForRequest(__CFDictionary const*, __CFSet const*, CFComparisonResult (*)(void const*, void const*, void*), void*, unsigned long, TCFRef<__CFArray const*>*) const + 2374
    frame #24: 0x000000011680d747 CoreText`TDescriptorSource::CopySystemWideFallbackDescriptorForCharacters(TBaseFont const&, unsigned short const*, long, UIFontFlag, TCFRef<__CFArray const*>*) const + 681
    frame #25: 0x000000011680ee03 CoreText`TDescriptorSource::CopySystemWideFallbackDescriptorForString(TBaseFont const&, __CFString const*, CFRange, UIFontFlag, TCFRef<__CFArray const*>*) const + 199
    frame #26: 0x00000001167f9ab3 CoreText`TFontCascade::CreateSystemWideFallback(__CTFont const*, __CFString const*, CFRange) const + 115
    frame #27: 0x00000001167f99ad CoreText`TFontCascade::CreateFallback(__CTFont const*, __CFString const*, CTEmojiPolicy) const + 1525
    frame #28: 0x00000001167c9204 CoreText`TGlyphEncoder::AppendUnmappedCharRun(unsigned int, TCFRef<CTRun*>&, __CTFont const*, CFRange, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const&, TGlyphEncoder::ClusterMatching) + 510
    frame #29: 0x00000001167c8e93 CoreText`TGlyphEncoder::RunUnicodeEncoderRecursively(unsigned int, TCFRef<CTRun*>&&, __CTFont const*, CFRange, TGlyphList<TDeletedGlyphIndex>&, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*, TGlyphEncoder::ClusterMatching, bool) + 1819
    frame #30: 0x00000001167c8703 CoreText`TGlyphEncoder::RunUnicodeEncoder(TCFRef<CTRun*>&&, __CTFont const*, CFRange, TGlyphList<TDeletedGlyphIndex>&, TFontCascade const*) + 137
    frame #31: 0x00000001167c82e0 CoreText`TGlyphEncoder::EncodeChars(CFRange, TAttributes const&, TGlyphList<TDeletedGlyphIndex>&, TGlyphEncoder::Fallbacks) + 1684
    frame #32: 0x00000001167df8a8 CoreText`TTypesetterAttrString::Initialize(__CFAttributedString const*) + 526
    frame #33: 0x00000001167cbe34 CoreText`CTLineCreateWithAttributedString + 63
    frame #34: 0x000000011cdffe3e UIFoundation`__NSStringDrawingEngine + 9479
    frame #35: 0x000000011cdfd824 UIFoundation`-[NSString(NSExtendedStringDrawing) drawWithRect:options:attributes:context:] + 167
    frame #36: 0x0000000114d69b4b UIKit`-[UILabel _drawTextInRect:baselineCalculationOnly:] + 6596
    frame #37: 0x0000000114d6788a UIKit`-[UILabel drawTextInRect:] + 669
    frame #38: 0x0000000114d69caf UIKit`-[UILabel drawRect:] + 100
    frame #39: 0x0000000114bab3e5 UIKit`-[UIView(CALayerDelegate) drawLayer:inContext:] + 495
    frame #40: 0x00000001148237ea QuartzCore`-[CALayer drawInContext:] + 257
    frame #41: 0x000000011508ab47 UIKit`-[_UILabelContentLayer drawInContext:] + 197
    frame #42: 0x0000000114712faa QuartzCore`CABackingStoreUpdate_ + 2725
    frame #43: 0x00000001148234d4 QuartzCore`___ZN2CA5Layer8display_Ev_block_invoke + 68
    frame #44: 0x000000011482334a QuartzCore`CA::Layer::display_() + 1614
    frame #45: 0x0000000114817e87 QuartzCore`CA::Layer::display_if_needed(CA::Transaction*) + 293
    frame #46: 0x0000000114817f17 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 35
    frame #47: 0x000000011480c3c9 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 277
    frame #48: 0x000000011483a086 QuartzCore`CA::Transaction::commit() + 486
    frame #49: 0x000000011483a7f8 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
    frame #50: 0x0000000118485c37 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    frame #51: 0x0000000118485ba7 CoreFoundation`__CFRunLoopDoObservers + 391
    frame #52: 0x000000011847b7fb CoreFoundation`__CFRunLoopRun + 1147
    frame #53: 0x000000011847b0f8 CoreFoundation`CFRunLoopRunSpecific + 488
    frame #54: 0x0000000119682ad2 GraphicsServices`GSEventRunModal + 161
    frame #55: 0x0000000114af0f09 UIKit`UIApplicationMain + 171

大致可以看到歉提, 是UILabel在 drawTextInRect時笛坦,獲取某些字元信息時出異常了。
我們的目的就是想看一下到底是什么文字引起這個問題的苔巨。

我們都知道 text 是存放在 UILabel.text 的屬性上版扩,第一印象都認(rèn)為 po self.text 就可以看到罪魁禍?zhǔn)琢恕?/p>

OK, 我們看一下實際輸出結(jié)果侄泽。

(lldb) po self.text
error: use of undeclared identifier 'self'
error: 1 errors parsing expression

可以看到提示礁芦,沒有找到 self ,因為當(dāng)前棧幀已經(jīng)去到

    frame #0: 0x0000000118914c6b libc++abi.dylib`__cxa_throw
    frame #1: 0x00000001311c782f libType1Scaler.dylib`TType1LWFNMultipleMasterHFMXTable::TType1LWFNMultipleMasterHFMXTable(TFontObjectSurrogate const&, int, short, short, int*) + 121
 

所以提示沒找到self也是很正常悼尾, 那么我們切換一下當(dāng)前堆棧宴偿,把它切換到 [UILabel drawRect:] 這個函數(shù)里面:

UIKit`-[UILabel drawRect:]:
   0x114d69c4b <+0>:   pushq  %rbp
   0x114d69c4c <+1>:   movq   %rsp, %rbp
   0x114d69c4f <+4>:   pushq  %rbx
   0x114d69c50 <+5>:   subq   $0x48, %rsp
   0x114d69c54 <+9>:   movq   %rdi, %rbx
   0x114d69c57 <+12>:  testq  %rbx, %rbx
   0x114d69c5a <+15>:  je     0x114d69c71               ; <+38>
   0x114d69c5c <+17>:  movq   0xa6c4ad(%rip), %rdx      ; "bounds"
   0x114d69c63 <+24>:  leaq   -0x30(%rbp), %rdi
   0x114d69c67 <+28>:  movq   %rbx, %rsi
   0x114d69c6a <+31>:  callq  0x1155c2af6               ; symbol stub for: objc_msgSend_stret
   0x114d69c6f <+36>:  jmp    0x114d69c7c               ; <+49>
   0x114d69c71 <+38>:  xorps  %xmm0, %xmm0
   0x114d69c74 <+41>:  movaps %xmm0, -0x20(%rbp)
   0x114d69c78 <+45>:  movaps %xmm0, -0x30(%rbp)
   0x114d69c7c <+49>:  movq   0xa7cdd5(%rip), %rsi      ; "drawTextInRect:"
   0x114d69c83 <+56>:  movq   -0x18(%rbp), %rax
   0x114d69c87 <+60>:  movq   %rax, 0x18(%rsp)
   0x114d69c8c <+65>:  movq   -0x20(%rbp), %rax
   0x114d69c90 <+69>:  movq   %rax, 0x10(%rsp)
   0x114d69c95 <+74>:  movq   -0x30(%rbp), %rax
   0x114d69c99 <+78>:  movq   -0x28(%rbp), %rcx
   0x114d69c9d <+82>:  movq   %rcx, 0x8(%rsp)
   0x114d69ca2 <+87>:  movq   %rax, (%rsp)
   0x114d69ca6 <+91>:  movq   %rbx, %rdi
   0x114d69ca9 <+94>:  callq  *0xaf0531(%rip)           ; (void *)0x0000000117c64800: objc_msgSend
   0x114d69caf <+100>: addq   $0x48, %rsp
   0x114d69cb3 <+104>: popq   %rbx
   0x114d69cb4 <+105>: popq   %rbp
   0x114d69cb5 <+106>: retq   

再看看結(jié)果:

(lldb) po self.text
error: use of undeclared identifier 'self'
error: 1 errors parsing expression

同樣湘捎,也是沒有找到self標(biāo)識符。但是我們從上面的匯編代碼可以看到窄刘,在調(diào)用 drawTextInRext 的時候窥妇,實際上最后也是調(diào)用 objc_msgSend 這個函數(shù)。

然后我們再看一下 objc_msgSend 的函數(shù)原型:

OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)

可以清楚的看到娩践,傳給objc_msgSend的第一個參數(shù)就是 self 對象活翩。

而且從

    0x114d69c7c <+49>:  movq   0xa7cdd5(%rip), %rsi      ; "drawTextInRect:"
    0x114d69c83 <+56>:  movq   -0x18(%rbp), %rax
    0x114d69c87 <+60>:  movq   %rax, 0x18(%rsp)
    0x114d69c8c <+65>:  movq   -0x20(%rbp), %rax
    0x114d69c90 <+69>:  movq   %rax, 0x10(%rsp)
    0x114d69c95 <+74>:  movq   -0x30(%rbp), %rax
    0x114d69c99 <+78>:  movq   -0x28(%rbp), %rcx
    0x114d69c9d <+82>:  movq   %rcx, 0x8(%rsp)
    0x114d69ca2 <+87>:  movq   %rax, (%rsp)
    0x114d69ca6 <+91>:  movq   %rbx, %rdi
    0x114d69ca9 <+94>:  callq  *0xaf0531(%rip)           ; (void *)0x0000000117c64800: objc_msgSend
    

這里可以看到, 在 drawRect 里面翻伺,實際上是調(diào)用了 drawTextInRect,根據(jù)一些調(diào)用約定材泄,可以判斷 objc_msgSend 的第一個參數(shù)是最后壓棧的,這時候我們可以猜測就是 rbx的寄存器的值吨岭。

我們可以通過 register read 指令查看當(dāng)前寄存器的值拉宗。

(lldb) register read
General Purpose Registers:
       rbx = 0x00007f9f833d71e0
       rbp = 0x00007fff5096bf70
       rsp = 0x00007fff5096bf20
       r12 = 0x00007f9f83102850
       r13 = 0x00007f9f833d71e0
       r14 = 0x0000000000000020
       r15 = 0x00007f9f80f119f0
       rip = 0x0000000114d69caf  UIKit`-[UILabel drawRect:] + 100
13 registers were unavailable.

然后我們嘗試一下輸出 rbx 的對象類型(如果它是一個對象的話)

(lldb) po [(id)$rbx class]
UILabel

可以看到rbx就是我們要找的那個UILabel對象,既然找到UILabel辣辫,那么就很容易找到相應(yīng)的 text 了旦事。

(lldb) po [(id)$rbx text]
? ?Amy??晴天冠 ??˙??

可以看到 ** ? ?Amy??晴天冠 ??˙?? ** 是這個文本引起異常。

如果不好判斷哪些寄存器是存放 self 對象的話急灭,可以一個一個打印一下類型試試姐浮。

總結(jié)

  • 很多時候異常了,而且不在我們的函數(shù)里面葬馋,這個時候直接取 self 是取不到的卖鲤。
  • 所有方法最終都調(diào)用了objc_msgSend, 調(diào)用的對象會作為第一個參數(shù)(self)傳給它畴嘶。
  • 可以通過查看寄存器命令 register read蛋逾, 獲取到self地址。
  • 也可以通過frame 指令查看當(dāng)前棧的參數(shù)信息窗悯。 具體可以看看 help frame 的輸出信息换怖。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蟀瞧,隨后出現(xiàn)的幾起案子沉颂,更是在濱河造成了極大的恐慌,老刑警劉巖悦污,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铸屉,死亡現(xiàn)場離奇詭異,居然都是意外死亡切端,警方通過查閱死者的電腦和手機彻坛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昌屉,你說我怎么就攤上這事钙蒙。” “怎么了间驮?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵躬厌,是天一觀的道長。 經(jīng)常有香客問我竞帽,道長扛施,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任屹篓,我火速辦了婚禮疙渣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堆巧。我一直安慰自己妄荔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布谍肤。 她就那樣靜靜地躺著啦租,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谣沸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天笋颤,我揣著相機與錄音乳附,去河邊找鬼。 笑死伴澄,一個胖子當(dāng)著我的面吹牛赋除,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播非凌,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼举农,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了敞嗡?” 一聲冷哼從身側(cè)響起颁糟,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喉悴,沒想到半個月后棱貌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡箕肃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年婚脱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡障贸,死狀恐怖错森,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情篮洁,我是刑警寧澤涩维,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站嘀粱,受9級特大地震影響激挪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锋叨,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一垄分、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娃磺,春花似錦薄湿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至听诸,卻和暖如春坐求,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晌梨。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工桥嗤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仔蝌。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓泛领,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敛惊。 傳聞我的和親對象是個殘疾皇子渊鞋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,682評論 0 9
  • 文中的實驗代碼我放在了這個項目中瞧挤。 以下內(nèi)容是我通過整理[這篇博客] (http://yulingtianxia....
    茗涙閱讀 913評論 0 6
  • 消息發(fā)送和轉(zhuǎn)發(fā)流程可以概括為:消息發(fā)送(Messaging)是 Runtime 通過 selector 快速查找 ...
    lylaut閱讀 1,821評論 2 3
  • 前言 runtime其實在我們?nèi)粘i_發(fā)過程中很少使用到锡宋,尤其是像我現(xiàn)在比較初級的程序猿就更用不到了。但是去面試很多...
    WolfTin閱讀 611評論 0 2
  • 七月份,在西安的營養(yǎng)界發(fā)生了一場血雨腥風(fēng)的戰(zhàn)事--講師大賽鸵鸥。而這場大賽最吸引我的就是在京城復(fù)賽之后奠滑,第一名可以獲得...
    水默語閱讀 247評論 4 1