From 08550bc7516c5d52bf4c6b2c30d962d7de47ded7 Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Tue, 9 Dec 2014 17:03:30 +0000 Subject: [PATCH] Initial dsymutil tool commit. The goal of this tool is to replicate Darwin's dsymutil functionality based on LLVM. dsymutil is a DWARF linker. Darwin's linker (ld64) does not link the debug information, it leaves it in the object files in relocatable form, but embbeds a `debug map` into the executable that describes where to find the debug information and how to relocate it. When releasing/archiving a binary, dsymutil is called to link all the DWARF information into a `dsym bundle` that can distributed/stored along with the binary. With this commit, the LLVM based dsymutil is just able to parse the STABS debug maps embedded by ld64 in linked binaries (and not all of them, for example archives aren't supported yet). Note that the tool directory is called dsymutil, but the executable is currently called llvm-dsymutil. This discrepancy will disappear once the tool will be feature complete. At this point the executable will be renamed to dsymutil, but until then you do not want it to override the system one. Differential Revision: http://reviews.llvm.org/D6242 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223793 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../dsymutil/Inputs/basic-lto.macho.x86_64 | Bin 0 -> 8912 bytes .../dsymutil/Inputs/basic-lto.macho.x86_64.o | Bin 0 -> 4516 bytes test/tools/dsymutil/Inputs/basic.macho.x86_64 | Bin 0 -> 9320 bytes test/tools/dsymutil/Inputs/basic1.c | 25 +++ .../dsymutil/Inputs/basic1.macho.x86_64.o | Bin 0 -> 2376 bytes test/tools/dsymutil/Inputs/basic2.c | 22 ++ .../dsymutil/Inputs/basic2.macho.x86_64.o | Bin 0 -> 3472 bytes test/tools/dsymutil/Inputs/basic3.c | 20 ++ .../dsymutil/Inputs/basic3.macho.x86_64.o | Bin 0 -> 3008 bytes test/tools/dsymutil/debug-map-parsing.test | 48 +++++ tools/CMakeLists.txt | 1 + tools/LLVMBuild.txt | 2 +- tools/Makefile | 2 +- tools/dsymutil/CMakeLists.txt | 12 ++ tools/dsymutil/DebugMap.cpp | 84 ++++++++ tools/dsymutil/DebugMap.h | 131 ++++++++++++ tools/dsymutil/DwarfLinker.cpp | 22 ++ tools/dsymutil/DwarfLinker.h | 40 ++++ tools/dsymutil/LLVMBuild.txt | 22 ++ tools/dsymutil/MachODebugMapParser.cpp | 194 ++++++++++++++++++ tools/dsymutil/MachODebugMapParser.h | 76 +++++++ tools/dsymutil/Makefile | 17 ++ tools/dsymutil/dsymutil.cpp | 67 ++++++ 23 files changed, 783 insertions(+), 2 deletions(-) create mode 100755 test/tools/dsymutil/Inputs/basic-lto.macho.x86_64 create mode 100644 test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o create mode 100755 test/tools/dsymutil/Inputs/basic.macho.x86_64 create mode 100644 test/tools/dsymutil/Inputs/basic1.c create mode 100644 test/tools/dsymutil/Inputs/basic1.macho.x86_64.o create mode 100644 test/tools/dsymutil/Inputs/basic2.c create mode 100644 test/tools/dsymutil/Inputs/basic2.macho.x86_64.o create mode 100644 test/tools/dsymutil/Inputs/basic3.c create mode 100644 test/tools/dsymutil/Inputs/basic3.macho.x86_64.o create mode 100644 test/tools/dsymutil/debug-map-parsing.test create mode 100644 tools/dsymutil/CMakeLists.txt create mode 100644 tools/dsymutil/DebugMap.cpp create mode 100644 tools/dsymutil/DebugMap.h create mode 100644 tools/dsymutil/DwarfLinker.cpp create mode 100644 tools/dsymutil/DwarfLinker.h create mode 100644 tools/dsymutil/LLVMBuild.txt create mode 100644 tools/dsymutil/MachODebugMapParser.cpp create mode 100644 tools/dsymutil/MachODebugMapParser.h create mode 100644 tools/dsymutil/Makefile create mode 100644 tools/dsymutil/dsymutil.cpp diff --git a/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64 b/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..b5ffb03c984d194795e1f3eef2c9ce6b382366a2 GIT binary patch literal 8912 zcmeHNOH30%7@h^H1Q0l2;tQ+>2})=&0YajOqBMdMK!wDpWU{3tRQn)wi^WI8sE3A_ z$VG2@HF`68(@4TWZ*ubJ&4i10!@>G}+gUm#M2$x?fAa7A-~5l6`F1X|v!6G<|J*5r zRVl<`g%F|%5)>(&2IUc?=ULNA+b6{N* z#@vJt%DGXbbYeNDXcuvLy-))d1BVwvTvZAuSk$4E+0>1ADk|ft=` zZ!X22@@HwC1O4Ounh)zKTc@{PZJnTfv$m8`+p$aeQf^;wb8V>eyLm|&$z)39u+H*& zRce0KT8v)LoxA2M?Tg`|k#pgJA@7~~x2zMGvZjjhed@IiW8ZbT5r262gF#90wSTFOqFLmKKeNb=SLcGVTwMt`S{EG`2CzcGH z3Sb`bNHMz&4ae*93&D4HRN+2gN(YpF;t*ORh5^HXVZbn87%&VN1`Gp+0mHz*GcYlj z|F+IU&E#ss!2z5HfR}tP(P90_e_Zc`v9#+so{!F3`Q1-w3|CuAz6Z3%&~*!j^@-Vw zuvGpvSoaGZw`&S3dEX?!clS)ovXiH-wMir(_P!*fM9TIySM#-Po!WgX5Fjiu9& zdo1Gl#E4XFs1BL;^fMLKeU>GnA7zPXj|2YGe#Ql1OOwPzyE;f~QVsa*C zM`Ls1P|}X4#1Vc}s1z$LiiVYz#t_YouXVhZKMD1&SDVmB7p^$nz8z?pU8`MP0=l0f zTt}2h3GZ)p+yp#bX^Gj_cgGpRK>~Pq_xnA-ts17k73$u-q9q=|L&wY?!#5H7PC%LO zVfHaU1f>u&KSTf_X8vQ99|C5+hv{cNl|syX4~K!(CPd#^Vt$lScvShT6=qD7 z4<%R8)&qO&1RiU zP(L?Ne6O$y|TAEkQUP2LUK9{Gh)vPId3Ou-4t?mEH(7n-lbbTo)ajilvE-5Z^Cmjuvg* z>b=|gdrP{jITP}EXbd+hRnJaOog_H%{lUz@_#r==J2=WV-{1N|=dSIpTREP1z&5=v z@%4kR!8S>cRUBVxU|=jWF_-U6v99GHK|Yf_t!AFp`NmSYLz%*y_|BMtR_clnT&%N| zD~L}*t;#o&N}H4`^WDM0Dw88-(8?N=s>(N<&1GnHH@+W)!tvcid=h$fzR|StsN{>v z8uEp2WyDs(@q6c6D2`R-J0g6Sh3|~;iAty%pG?P`e3#0gw+X?vsI9C=d@{6^e5qne zi~-2Ev$wOP_Y0q!mZRXigP>$;YQ8^ED3rBT^0|FgzU<2RWLeHK_)CgAJ z-1*%n@m&{>6OwN~@{QTHa(d)v`9=p0n+dL*->uy2kR=w>plmWx303(_eEC$ml5ePj zZ}NZg6_4es=KHqr9h87B3E$Pb&To2j1aTGp@!ZSV+@SCGY%R-0-4eb7(zpPF#(i-e zeAV|yX2?G{hS{(VzJKTW*Dn)$PWX-rpQsAUd&t#^9Lxo*;DBW)dEgo#x4}*n3a6Nb zYeT|C?fzs>*VG?ojqIOpT!ayze#Y!QeQW9`({siQ<=N-;)C1%`+Y{E-;_Oao(pTwy zlD#GWH)ftVQ9pBK%8>1!o~7GA{R-^tVhNjN9aWp@3hA<7o&lz*AJklqdUpA{V?g%> zKR5mC4(@r+3tlqnVLp46w+C3`)$s19;aw3rhKKhRYg+vbxHEvgXxW5P9zg8?8c0vk zIuyK69`wnwkv zv6wYTy9K4^sfN?2>zFge=zNEUJ2QF*Eqr}>MzIgk@HC3ni1N=cYLG_96aN^Ru5~KH zzQBffS=esrx$D=39d}Mk;nCEK2j!3j)qGJZx*4~#2|nT+5WH^EOJglH!B{->aI6Va z9Z2e6Y-8l9$Yas&md(-jNRw{X9rc*#8f81WTLMtMB~Uj-B3KkPjjFo^le^47?HY7+ z$2Uhwf{zTVQlVR2Qdmfh&yTXV!KL)J$n4wV0qnErLba-ek@QFQ!mYuvbjRBx2{gpa zTM(~%PvctEjd_lj4DAb>BFMNIc{Y=APssAAl^7(MLp1}DF;i}-INf27v40)Uu(5Z` z(OpSy6*}GVbU1KpwXC?f39*FL}F6g3a*${YGF5{CR`~)II!Hm;7BO!A4!b{mAaq zt?vc`pm4O0f{GGUI9F`7^mM+yG#R6;C?n;KB_CVsFIkmF_9T7WJhy}b;-8G z^7Jr1AzRnAwI$nJC`3X7Su>8n^W0b(e`k7 z#&hHF^auInk{`=Xq>34QK-1v3^sQ0{M@Qk5woV+AiPW%kwxe-OrN$1W`Iu1YA*(94 zpI?-eT<&gvS7r+Rag?szon4rHb2ssRl1~tGUupRY=0fLc2%@mg+k$u6qLY)69}i4M z4zK+6_SLU}uYGi4sxTS3j5Z!VlPKp=zCigF$-M5zhViq^BN>Ea!|@8L8hoqb zq%pcuZ5X3;;)4?%(08No&SMPRWwJ?m;jxLgU)6nU*^CWLO5*my2HWIPn>BFTKuG8G zyV&*dT}mH~>v*&_d=6H$e*|UnZ;r~$jJ#i|&RG0Z;F$)_J%x5#QSxFZaa6S%hMnV+ zc;?t~&LOQF8-%ftb4Tn1dcgI9Ng&31A@4CF4;0Kr>wF;X&DRX{8&L2IT@#!Z{9f=a zAaV<>6Fn&y74!tJffrX&i0ha3=5_|IvF{6gDtJ!%4~Wk3r(XwTDdj&nt0d+xdNOVDOP;^1>farqWKG6lee$fRz zjtl;p_6mBOFY1C`2Xy9<5Cj;V=S~bA%!7g$RSW~>E;oEuoBo~bgm9kO?=I8D)G^TR rGF?s`PVRdi)T)sWC%!qBeIBzuk5->&s$YH@qvg2T)@A=Kw88H`Kt0gU literal 0 HcmV?d00001 diff --git a/test/tools/dsymutil/Inputs/basic.macho.x86_64 b/test/tools/dsymutil/Inputs/basic.macho.x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..8b3a34a55977502ad5975d524ba358044ea28d26 GIT binary patch literal 9320 zcmeHNTWB0r7(QdNy0)H!0j4|#rB?GVI!tZite;(e*ZqaPG)Xs&C zUzavtZMXOY-8|ZM)|-iKc5SR| z@PR&j`Ztu$dU!c9n%ch%ENHKpxQbRn%}RWOrr}ciLtraQZQ4$~e;dlyIEpa4_2V6= z5zGgun#qBq?QpYoVtacVL(S|~dQr&Ie^F(dMa>Asr2vaWn4!^_Ge!9AP=F>5~G z^Z9=QHT5I>My0UL-;_gm?jP>_YN44OVZ>G}1C{~HfMvikU>UFsSOzQumI2FvWxz6E z8Tg+w;7FXWCuC(#mKIBeMo^M-C9hao5Tg~(uZoFsttOt#dkf;3Q{KFIj_(=<#JPJ> zTw!tPJ`}4idPZkl9GG6aI>ckrr=a>h!(Q}}L>yJBzME0g%x>cd5)gJE9MET?#5{*J z@m}EafFs`c^zB)W(@7eIKKCC39x*V-M`A^#<{v{R`zRbQvWTVEKhIE2|5L#I{9nQQ z7n+e!`q!9!^aW~^5YxYj8NVBUXFy+EuQBIy{hd$>G1qI%7exoi91dkURwc$2(C6>$ zyHS2;I1bgaiblWu4#)9*h;hcJG3_%xGoOC>t;Orl$LlrL>v{f9A?A9GF95qxEgU!V z`2=_mIyGOP#aP?_oY>&!60yP0*T5+URRlkEMGj z^Y+BID+M9*-djSRT<}kMxQG2}5cwPLH8K7d6TG=26THKtR)34K&%X)y#c~yf3S80% SKWvcoppln(d|QKmCgM*oFj4UU literal 0 HcmV?d00001 diff --git a/test/tools/dsymutil/Inputs/basic1.c b/test/tools/dsymutil/Inputs/basic1.c new file mode 100644 index 00000000000..04e8f9391d1 --- /dev/null +++ b/test/tools/dsymutil/Inputs/basic1.c @@ -0,0 +1,25 @@ +/* This is the main file used to produce the basic* objects that are + used for the dsymutil tests. + + These are compiled in a couple of different ways (always on a + Darwin system): + Basic compilation: + for FILE in basic1.c basic2.c basic3.c; do + clang -g -c $FILE -o ${FILE%.c}.macho.x86_64.o + done + clang basic1.macho.x86_64.o basic2.macho.x86_64.o basic3.macho.x86_64.o -o basic.macho.x86_64 -Wl,-dead_strip + + LTO compilation: + for FILE in basic1.c basic2.c basic3.c; do + clang -g -c -flto $FILE -o ${FILE%.c}-lto.o + done + clang basic1-lto.o basic2-lto.o basic3-lto.o -o basic-lto.macho.x86_64 -Wl,-object_path_lto,$PWD/basic-lto.macho.x86_64.o -Wl,-dead_strip + rm basic1-lto.o basic2-lto.o basic3-lto.o + +*/ + +int foo(int); + +int main(int argc, const char *argv[]) { + return foo(argc); +} diff --git a/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o b/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o new file mode 100644 index 0000000000000000000000000000000000000000..d7b5000a612725b609a76703ad05531fd6112f9f GIT binary patch literal 2376 zcmb7GO-vI}5Pq+J{Irx}jsJ;z0E9$J6(uT0AcAQVjD|nupv!hypoDIl{va5L7!o7l zq6aUYJZQqrt49(|^v1!9M=nMWns{vd!;*MENhTfrE2 zGMHeX9(BW{zyLW4Bk!`zl9PfPKo)Tii1dMz;i$z$5LL|@vsqyaf3WxV;Fd3~dNPm? zU;Cm`#0Acx#GqEyF(a0nP~+x!QusZ$y8EvcAd=@Ht-Pf8R)NnU)<_9Q@@cVH+L%H9 zV!l_zGeEk*L&laW&6n292_v(EFHifzq-Tlmjm)%%A4{w{SmKoo4 z+%$08ZhW1@Df!m+h;KTnTRZH06Snxilo?+poBl7~B*j-QA05YzeAjL9-N5E87Tfu1 zsnoQgnpy%*cW3=1-(}*Ed>?l0Kf#xbO<4uB*Uw9DmwmmmpZHRmZs%*Y@x3mSFFThi znePDcjZ?lKiSHBSi{CMbt$unk0dZy3oOv&9j;U&2kAR7JjnE1$b^#AwHF?l#7I$iq{KObJwzH5ZD?m#ZCh= z<-|5Yz_moiD}AXuz;LjWFmwLPUjwt1BgDd4Ov}XeGa(EXq)O0&PhSsQ= z%4IVwp~X!WH?vGjPv|(!Fnv->v&cYq1Zyvc4`^fOf+tiH$7c3NJqP>dLeEF7WZ^4O;=@#d^|lpovS^6s1py zRuNPr^5y(~KjX6j9`IFEJ^>WsPayISrnR|QVD0t?9yzYo$e)K}0D&Z0@E(P2o^zxF zq_L2=-UJ#NZjiJK@ipL+c3mK!vZ>b(BPn5Na|N5Ni1&iTs}o?Q|ptCz3ewt?dewY;Dta6BjTe z7}&B0=ZoRV_@qAbBCj|TNPIwz@yS;bA29Ke2myb;`<>ga-KKcb`~B{@=iJ{t=l=V? z-u?T}$6X>$Q1Cz@N*E=@ipX;)*F&bd>SJ7ODfWSksSZwI>0=|r^BTnq4ZrT|BgamS zv~*j$rWNwJsLw`4y4mK+EWwKBjTiG%XT4JSOoeTpH~7K8i8rlTEYEM+@{PuK$MT5; zn$D)b&zH;RYsKl6e5W}%kk5ROOH8g^R_Ckb%4du974h9yzIT-)7V#^In6AMZ@lECm zCgsk2544RgGOB#bLTvM}^EXi{7wNMW-`h%H`L-ZF4SjXKO2PE#-YQ0qyL=0W${&Wg-$+m_`zlQQawuCf>q;dd|X{M-+rCAx3vGD@+~4+ zCFw& z`4*M$FXdBJaBZElbt1{1MY)ObIMvy8C_wm$y;DfZ!gzRHwFLzIY2^Lv{Jrdz`-z2v z^!|g7`D2f=SAIyGUh3U^M65l#U@rdoOOF=ti#T`H^?|{K;}4u$>T&z>ZEn_iL+IR^ zzhlW}NlrfBF=V_9>*=LmVDiI{n4KPz!}NwQX)6I{egMUB!rei81cRe!3Ayf=HM-rw z=5d;^jlu3G|$vV=oIH<_yQs6_=BX_2r2mhd)F+gPLk%p=NBb%k!sv{ zlazAJ2RMt<=e!tChJx`#`1yDrh70VGV0*z&)IH{Kl7KWN8_?Lh3z~ByGfY9!j=+WEhd@B+C;>bCNV-JE0NPE!d2# zZjo=}fNaLoaURCk;c2E6c{-BM)k}q4>4NXu-Q1eNZl~v+dv|*xF9c@-hfohB(Qklv zS!#Ir`|o`Ro$g_p_=sn$x%RT#Z`{a!KQyuGGjc0}5W%yw8 zZ^9?1!4H9uO~)1A03y5{`+!}*SAY?bgT1QbFjF@DhzI<_ONw7Aexdk@BFCX0Uqiew zxTkQrgt;cvGipz%o&eImUE9Zj*e4^3?wIO|?x^aDF83z=72Ofl6 42) + return inc(); + return foo(val + arg); +} diff --git a/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o b/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o new file mode 100644 index 0000000000000000000000000000000000000000..3c1c6399fd890c31b0bdf0e31ad1506522878f49 GIT binary patch literal 3008 zcmb7G%WGU!96om*nMo#@OpHoJF?SI)6*CS^TKX_;f{C4!1ZqrcH{s4?GLwuiZoF*-OEOE--W$El>(DsJ1=XD6=A z9_Xf3lLq-neX&ESHrjk@gJ8sQ7Si+8MJJoj6limt@i)h2UNdfGcy5ZNU6Uxa0Y2sh z@wnjDhA%lkUrMhu^PT17Kn(9U!sl9b-I}kI%rB} z54mx?fx2j=J`leD%P*JBry27wz6(NN_;!$=q+a($Gk>{4O802wd%Z4Nsh2tpF2Zq=#bPe)?cvGARj{GMoc8|xE&m){(c$dWdbqlaZC7It5Tp{ zGHoKskD#1{gGc=aZ~zEU7f~pTF@^MX2{GUhaw%TB7vIvC=hn$z*CXhiR`k}j3Ag}i+t8nXvdIXpyz zCt|T^EIM@Rs67DM^nwkyjva~~FR$c}9(?TO$$YU|DXW!aPG$2IRn1ose+&U7=qZ&f zEvon%V{xRYN67=w$pj&^S?;r~XM;M^-nqFM`YN#*3jKWgOy9<4h?^;a!j;`Xq0ZRn zQ78!%>We58y|sX5N9xT1{S!JNCLi{pH0HyVdDIwkneEFB&vAK`A7kcKpi~Uw7zT3p zGj)jb;twpRzXCQbTQB2_(luz$-(0h9( zPK|{l?|WYDGQTg3DNI z^H2NdK&0FDnc%u$Rd7!5lHf29{ld2B5z$`~eF}(EIxFbo_o)l|I6mrvzERNyeKF{` zUuOlipZVFa69F1I{xA$?eV(O`pWRUmj>7rwhTokV W1Ui{QK{-5o_~T8fiMadL#neAZ;!#2X literal 0 HcmV?d00001 diff --git a/test/tools/dsymutil/debug-map-parsing.test b/test/tools/dsymutil/debug-map-parsing.test new file mode 100644 index 00000000000..11d2fa77091 --- /dev/null +++ b/test/tools/dsymutil/debug-map-parsing.test @@ -0,0 +1,48 @@ +RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic.macho.x86_64 | FileCheck %s +RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO +RUN: llvm-dsymutil -v -parse-only %p/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=NOT-FOUND +RUN: not llvm-dsymutil -v -parse-only %p/Inputs/inexistant 2>&1 | FileCheck %s --check-prefix=NO-EXECUTABLE +Check that We can parse the debug map of the basic executable. + +CHECK-NOT: error +CHECK: DEBUG MAP: +CHECK: /Inputs/basic1.macho.x86_64.o: +CHECK: 0000000000000000 => 0000000100000ea0 _main +CHECK: /Inputs/basic2.macho.x86_64.o: +CHECK: 0000000000000310 => 0000000100001000 _baz +CHECK: 0000000000000020 => 0000000100000ed0 _foo +CHECK: 0000000000000070 => 0000000100000f20 _inc +CHECK: 0000000000000560 => 0000000100001008 _private_int +CHECK: /Inputs/basic3.macho.x86_64.o: +CHECK: 0000000000000020 => 0000000100000f40 _bar +CHECK: 0000000000000070 => 0000000100000f90 _inc +CHECK: 0000000000000004 => 0000000100001004 _val +CHECK: END DEBUG MAP + + +Check that we can parse the debug-map of the basic-lto executable + +CHECK-LTO-NOT: error +CHECK-LTO: DEBUG MAP: +CHECK-LTO: /Inputs/basic-lto.macho.x86_64.o: +CHECK-LTO: 0000000000000050 => 0000000100000f90 _bar +CHECK-LTO: 0000000000000658 => 0000000100001000 _baz +CHECK-LTO: 0000000000000010 => 0000000100000f50 _foo +CHECK-LTO: 0000000000000000 => 0000000100000f40 _main +CHECK-LTO: 00000000000008e8 => 0000000100001008 _private_int +CHECK-LTO: 00000000000008ec => 0000000100001004 _val +CHECK-LTO: END DEBUG MAP + +Check that we warn about missing object files (this presumes that the files aren't +present in the machine's /Inputs/ folder, which should be a pretty safe bet). + +NOT-FOUND: cannot open{{.*}}"/Inputs/basic1.macho.x86_64.o": No such file +NOT-FOUND: cannot open{{.*}}"/Inputs/basic2.macho.x86_64.o": No such file +NOT-FOUND: cannot open{{.*}}"/Inputs/basic3.macho.x86_64.o": No such file +NOT-FOUND: DEBUG MAP: +NOT-FOUND-NEXT: END DEBUG MAP + +Check that we correctly error out on invalid executatble. + +NO-EXECUTABLE: cannot parse{{.*}}/inexistant": No such file +NO-EXECUTABLE-NOT: DEBUG MAP diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 9ea5543a0b3..7e9938119f5 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -36,6 +36,7 @@ add_llvm_tool_subdirectory(llvm-objdump) add_llvm_tool_subdirectory(llvm-readobj) add_llvm_tool_subdirectory(llvm-rtdyld) add_llvm_tool_subdirectory(llvm-dwarfdump) +add_llvm_tool_subdirectory(dsymutil) add_llvm_tool_subdirectory(llvm-vtabledump) if( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool_subdirectory(llvm-jitlistener) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 13a08b2d449..53d4ffc28dc 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index 4b8923a58d3..b559edacd52 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -33,7 +33,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \ macho-dump llvm-objdump llvm-readobj llvm-rtdyld \ llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \ llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \ - llvm-vtabledump verify-uselistorder + llvm-vtabledump verify-uselistorder dsymutil # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt new file mode 100644 index 00000000000..ead9848b087 --- /dev/null +++ b/tools/dsymutil/CMakeLists.txt @@ -0,0 +1,12 @@ +set(LLVM_LINK_COMPONENTS + Object + Support + ) + +add_llvm_tool(llvm-dsymutil + dsymutil.cpp + DebugMap.cpp + DwarfLinker.cpp + MachODebugMapParser.cpp + ) + diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp new file mode 100644 index 00000000000..c0e2393f3be --- /dev/null +++ b/tools/dsymutil/DebugMap.cpp @@ -0,0 +1,84 @@ +//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "DebugMap.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { + +using namespace llvm::object; + +DebugMapObject::DebugMapObject(StringRef ObjectFilename) + : Filename(ObjectFilename) {} + +bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress, + uint64_t LinkedAddress) { + auto InsertResult = Symbols.insert(std::make_pair(Name, + SymbolMapping{ObjectAddress, + LinkedAddress})); + return InsertResult.second; +} + +void DebugMapObject::print(raw_ostream& OS) const { + OS << getObjectFilename() << ":\n"; + // Sort the symbols in alphabetical order, like llvm-nm (and to get + // deterministic output for testing). + typedef StringMapEntry MapEntryTy; + std::vector Entries; + Entries.reserve(Symbols.getNumItems()); + for (auto SymIt = Symbols.begin(), End = Symbols.end(); SymIt != End; ++SymIt) + Entries.push_back(&*SymIt); + std::sort(Entries.begin(), Entries.end(), + [] (const MapEntryTy *LHS, const MapEntryTy *RHS) { + return LHS->getKey() < RHS->getKey(); + }); + for (const auto *Entry: Entries) { + const auto &Sym = Entry->getValue(); + OS << format("\t%016" PRIx64 " => %016" PRIx64 "\t%s\n", + Sym.ObjectAddress, Sym.BinaryAddress, Entry->getKeyData()); + } + OS << '\n'; +} + +#ifndef NDEBUG +void DebugMapObject::dump() const { + print(errs()); +} +#endif + +DebugMapObject& DebugMap::addDebugMapObject(StringRef ObjectFilePath) { + Objects.emplace_back(new DebugMapObject(ObjectFilePath)); + return *Objects.back(); +} + +const DebugMapObject::SymbolMapping * +DebugMapObject::lookupSymbol(StringRef SymbolName) const { + StringMap::const_iterator Sym = Symbols.find(SymbolName); + if (Sym == Symbols.end()) + return nullptr; + return &Sym->getValue(); +} + +void DebugMap::print(raw_ostream& OS) const { + OS << "DEBUG MAP: object addr => executable addr\tsymbol name\n"; + for (const auto &Obj: objects()) + Obj->print(OS); + OS << "END DEBUG MAP\n"; +} + +#ifndef NDEBUG +void DebugMap::dump() const { + print(errs()); +} +#endif +} diff --git a/tools/dsymutil/DebugMap.h b/tools/dsymutil/DebugMap.h new file mode 100644 index 00000000000..e7862e49f7a --- /dev/null +++ b/tools/dsymutil/DebugMap.h @@ -0,0 +1,131 @@ +//===- tools/dsymutil/DebugMap.h - Generic debug map representation -------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains the class declaration of the DebugMap +/// entity. A DebugMap lists all the object files linked together to +/// produce an executable along with the linked address of all the +/// atoms used in these object files. +/// The DebugMap is an input to the DwarfLinker class that will +/// extract the Dwarf debug information from the referenced object +/// files and link their usefull debug info together. +/// +//===----------------------------------------------------------------------===// +#ifndef DSYMUTIL_DEBUGMAP_H +#define DSYMUTIL_DEBUGMAP_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Format.h" +#include "llvm/ADT/iterator_range.h" +#include + +namespace llvm { + +class raw_ostream; + +class DebugMapObject; + +/// \brief The DebugMap object stores the list of object files to +/// query for debug information along with the mapping between the +/// symbols' addresses in the object file to their linked address in +/// the linked binary. +/// +/// A DebugMap producer could look like this: +/// DebugMap *DM = new DebugMap(); +/// for (const auto &Obj: LinkedObjects) { +/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath()); +/// for (const auto &Sym: Obj.getLinkedSymbols()) +/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(), +/// Sym.getBinaryAddress()); +/// } +/// +/// A DebugMap consumer can then use the map to link the debug +/// information. For example something along the lines of: +/// for (const auto &DMO: DM->objects()) { +/// auto Obj = createBinary(DMO.getObjectFilename()); +/// for (auto &DIE: Obj.getDwarfDIEs()) { +/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName())) +/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress); +/// else +/// DIE.discardSubtree(); +/// } +/// } +class DebugMap +{ + typedef std::vector> ObjectContainer; + ObjectContainer Objects; + +public: + typedef ObjectContainer::const_iterator const_iterator; + + iterator_range objects() const { + return make_range(begin(), end()); + } + + const_iterator begin() const { + return Objects.begin(); + } + + const_iterator end() const { + return Objects.end(); + } + + /// This function adds an DebugMapObject to the list owned by this + /// debug map. + DebugMapObject& addDebugMapObject(StringRef ObjectFilePath); + + void print(raw_ostream& OS) const; + +#ifndef NDEBUG + void dump() const; +#endif +}; + +/// \brief The DebugMapObject represents one object file described by +/// the DebugMap. It contains a list of mappings between addresses in +/// the object file and in the linked binary for all the linked atoms +/// in this object file. +class DebugMapObject { +public: + struct SymbolMapping { + uint64_t ObjectAddress; + uint64_t BinaryAddress; + }; + + /// \brief Adds a symbol mapping to this DebugMapObject. + /// \returns false if the symbol was already registered. The request + /// is discarded in this case. + bool addSymbol(llvm::StringRef SymName, uint64_t ObjectAddress, + uint64_t LinkedAddress); + + /// \bried Lookup a symbol mapping. + /// \returns null if the symbol isn't found. + const SymbolMapping *lookupSymbol(StringRef SymbolName) const; + + llvm::StringRef getObjectFilename() const { return Filename; } + + void print(raw_ostream& OS) const; +#ifndef NDEBUG + void dump() const; +#endif +private: + friend class DebugMap; + /// DebugMapObjects can only be constructed by the owning DebugMap. + DebugMapObject(StringRef ObjectFilename); + + std::string Filename; + StringMap Symbols; +}; + +} + +#endif // DSYMUTIL_DEBUGMAP_H diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp new file mode 100644 index 00000000000..6958bfa40e9 --- /dev/null +++ b/tools/dsymutil/DwarfLinker.cpp @@ -0,0 +1,22 @@ +//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "DwarfLinker.h" +#include "DebugMap.h" + +namespace llvm { + +DwarfLinker::DwarfLinker(StringRef OutputFilename) + : OutputFilename(OutputFilename) +{} + +bool DwarfLinker::link(const DebugMap &Map) { + return true; +} + +} diff --git a/tools/dsymutil/DwarfLinker.h b/tools/dsymutil/DwarfLinker.h new file mode 100644 index 00000000000..0f87f5a4f58 --- /dev/null +++ b/tools/dsymutil/DwarfLinker.h @@ -0,0 +1,40 @@ +//===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains the class declaration of the DwarfLinker +/// object. A DwarfLinker takes a DebugMap as input and links the +/// debug information of all the referenced object files together. It +/// may drop and rewrite some parts of the debug info tree in the +/// process. +/// +//===----------------------------------------------------------------------===// +#ifndef DSYMUTIL_DWARFLINKER_H +#define DSYMUTIL_DWARFLINKER_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +class DebugMap; + +class DwarfLinker { + std::string OutputFilename; +public: + DwarfLinker(StringRef OutputFilename); + + /// \brief Link the passed debug map into the ouptut file. + /// \returns false if the link encountered a fatal error. + bool link(const DebugMap&); +}; + +} + +#endif diff --git a/tools/dsymutil/LLVMBuild.txt b/tools/dsymutil/LLVMBuild.txt new file mode 100644 index 00000000000..29d95d2d8b6 --- /dev/null +++ b/tools/dsymutil/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/dsymutil/LLVMBuild.txt ---------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = dsymutil +parent = Tools +required_libraries = Object Support diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp new file mode 100644 index 00000000000..49d4949f8bb --- /dev/null +++ b/tools/dsymutil/MachODebugMapParser.cpp @@ -0,0 +1,194 @@ +//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MachODebugMapParser.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::object; + +namespace llvm { + +static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; } + +static ErrorOr> createMachOBinary(StringRef file) { + ErrorOr> BinaryOrErr = createBinary(file); + if (BinaryOrErr.getError()) + return BinaryOrErr.getError(); + + std::unique_ptr Bin; + std::unique_ptr Buf; + std::tie(Bin, Buf) = BinaryOrErr->takeBinary(); + if (!isa(Bin.get())) + return make_error_code(object_error::invalid_file_type); + + std::unique_ptr MachOFile(cast(Bin.release())); + return OwningBinary(std::move(MachOFile), std::move(Buf)); +} + +/// Reset the parser state coresponding to the current object +/// file. This is to be called after an object file is finished +/// processing. +void MachODebugMapParser::resetParserState() { + CurrentObjectFile = OwningBinary(); + CurrentObjectAddresses.clear(); + CurrentDebugMapObject = nullptr; +} + +/// Create a new DebugMapObject. This function resets the state of the +/// parser that was referring to the last object file and sets +/// everything up to add symbols to the new one. +void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) { + resetParserState(); + + std::string Path = Filename; + if (!PathPrefix.empty()) + Path = PathPrefix + sys::path::get_separator().data() + Path; + + auto MachOOrError = createMachOBinary(Path); + if (auto Error = MachOOrError.getError()) { + Warning(Twine("cannot open debug object \"") + Path + "\": " + + Error.message() + "\n"); + return; + } + + CurrentObjectFile = std::move(*MachOOrError); + loadCurrentObjectFileSymbols(); + CurrentDebugMapObject = &Result->addDebugMapObject(Path); +} + +/// This main parsing routine tries to open the main binary and if +/// successful iterates over the STAB entries. The real parsing is +/// done in handleStabSymbolTableEntry. +ErrorOr> MachODebugMapParser::parse() { + auto MainBinaryOrError = createMachOBinary(BinaryPath); + if (MainBinaryOrError.getError()) + return MainBinaryOrError.getError(); + + MainOwningBinary = std::move(*MainBinaryOrError); + Result = make_unique(); + const auto &MainBinary = *MainOwningBinary.getBinary(); + for (const SymbolRef &Symbol : MainBinary.symbols()) { + const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); + if (MainBinary.is64Bit()) + handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI)); + else + handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI)); + } + + resetParserState(); + return std::move(Result); +} + +/// Interpret the STAB entries to fill the DebugMap. +void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, + uint8_t Type, + uint8_t SectionIndex, + uint16_t Flags, + uint64_t Value) { + if (!(Type & MachO::N_STAB)) + return; + + const MachOObjectFile &MachOBinary = *MainOwningBinary.getBinary(); + const char *Name = &MachOBinary.getStringTableData().data()[StringIndex]; + + // An N_OSO entry represents the start of a new object file description. + if (Type == MachO::N_OSO) + return switchToNewDebugMapObject(Name); + + // If the last N_OSO object file wasn't found, + // CurrentDebugMapObject will be null. Do not update anything + // until we find the next valid N_OSO entry. + if (!CurrentDebugMapObject) + return; + + switch (Type) { + case MachO::N_GSYM: + // This is a global variable. We need to query the main binary + // symbol table to find its address as it might not be in the + // debug map (for common symbols). + Value = getMainBinarySymbolAddress(Name); + if (Value == UnknownAddressOrSize) + return; + break; + case MachO::N_FUN: + // Functions are scopes in STABS. They have an end marker that we + // need to ignore. + if (Name[0] == '\0') + return; + break; + case MachO::N_STSYM: + break; + default: + return; + } + + auto ObjectSymIt = CurrentObjectAddresses.find(Name); + if (ObjectSymIt == CurrentObjectAddresses.end()) + return Warning("could not find object file symbol for symbol " + + Twine(Name)); + if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value)) + return Warning(Twine("failed to insert symbol '") + Name + "' in the debug map."); +} + +/// Load the current object file symbols into CurrentObjectAddresses. +void MachODebugMapParser::loadCurrentObjectFileSymbols() { + CurrentObjectAddresses.clear(); + const auto &Binary = *CurrentObjectFile.getBinary(); + + for (auto Sym : Binary.symbols()) { + StringRef Name; + uint64_t Addr; + if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize || + Sym.getName(Name)) + continue; + CurrentObjectAddresses[Name] = Addr; + } +} + +/// Lookup a symbol address in the main binary symbol table. The +/// parser only needs to query common symbols, thus not every symbol's +/// address is available through this function. +uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { + if (MainBinarySymbolAddresses.empty()) + loadMainBinarySymbols(); + + auto Sym = MainBinarySymbolAddresses.find(Name); + if (Sym == MainBinarySymbolAddresses.end()) + return UnknownAddressOrSize; + return Sym->second; +} + +/// Load the interesting main binary symbols' addresses into +/// MainBinarySymbolAddresses. +void MachODebugMapParser::loadMainBinarySymbols() { + const MachOObjectFile &Binary = *MainOwningBinary.getBinary(); + section_iterator Section = Binary.section_end(); + for (const auto &Sym : Binary.symbols()) { + SymbolRef::Type Type; + // Skip undefined and STAB entries. + if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) || + (Type & SymbolRef::ST_Unknown)) + continue; + StringRef Name; + uint64_t Addr; + // The only symbols of interest are the global variables. These + // are the only ones that need to be queried because the address + // of common data won't be described in the debug map. All other + // addresses should be fetched for the debug map. + if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize || + !(Sym.getFlags() & SymbolRef::SF_Global) || + Sym.getSection(Section) || Section->isText() || Sym.getName(Name) || + Name.size() == 0 || Name[0] == '\0') + continue; + MainBinarySymbolAddresses[Name] = Addr; + } +} + +} diff --git a/tools/dsymutil/MachODebugMapParser.h b/tools/dsymutil/MachODebugMapParser.h new file mode 100644 index 00000000000..b4f48b6730f --- /dev/null +++ b/tools/dsymutil/MachODebugMapParser.h @@ -0,0 +1,76 @@ +//===- tools/dsymutil/MachODebugMapParser.h - Parse STABS debug maps ------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains the class declaration for the code that parses STABS +/// debug maps that are embedded in the binaries symbol tables. +/// +//===----------------------------------------------------------------------===// +#ifndef DSYMUTIL_MACHODEBUGMAPPARSER_H +#define DSYMUTIL_MACHODEBUGMAPPARSER_H + +#include "DebugMap.h" + +#include "llvm/ADT/StringMap.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/Error.h" + +namespace llvm { + +class MachODebugMapParser { +public: + MachODebugMapParser(StringRef BinaryPath) + : BinaryPath(BinaryPath) {} + + /// \brief Add a prefix to every object file path before trying to + /// open it. + void setPreprendPath(StringRef Prefix) { PathPrefix = Prefix; } + + /// \brief Parses and returns the DebugMap of the input binary. + /// \returns an error in case the provided BinaryPath doesn't exist + /// or isn't of a supported type. + ErrorOr> parse(); + +private: + std::string BinaryPath; + std::string PathPrefix; + + /// OwningBinary constructed from the BinaryPath. + object::OwningBinary MainOwningBinary; + /// Map of the binary symbol addresses. + StringMap MainBinarySymbolAddresses; + /// The constructed DebugMap. + std::unique_ptr Result; + + /// Handle to the currently processed object file. + object::OwningBinary CurrentObjectFile; + /// Map of the currently processed object file symbol addresses. + StringMap CurrentObjectAddresses; + /// Element of the debug map corresponfing to the current object file. + DebugMapObject *CurrentDebugMapObject; + + void switchToNewDebugMapObject(StringRef Filename); + void resetParserState(); + uint64_t getMainBinarySymbolAddress(StringRef Name); + void loadMainBinarySymbols(); + void loadCurrentObjectFileSymbols(); + void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, + uint8_t SectionIndex, uint16_t Flags, + uint64_t Value); + + template void handleStabDebugMapEntry(const STEType &STE) { + handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, + STE.n_value); + } +}; + +} + +#endif // DSYMUTIL_MACHODEBUGMAPPARSER_H diff --git a/tools/dsymutil/Makefile b/tools/dsymutil/Makefile new file mode 100644 index 00000000000..9eda7dcabc0 --- /dev/null +++ b/tools/dsymutil/Makefile @@ -0,0 +1,17 @@ +##===- tools/dsymutil/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-dsymutil +LINK_COMPONENTS := Object Support + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp new file mode 100644 index 00000000000..00052bc30ea --- /dev/null +++ b/tools/dsymutil/dsymutil.cpp @@ -0,0 +1,67 @@ +//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// + +#include "DebugMap.h" +#include "DwarfLinker.h" +#include "MachODebugMapParser.h" + +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Options.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + +#include + +static llvm::cl::opt InputFile(llvm::cl::Positional, + llvm::cl::desc(""), + llvm::cl::init("-")); + +static llvm::cl::opt OsoPrependPath("oso-prepend-path", + llvm::cl::desc("")); + +static llvm::cl::opt Verbose("v", llvm::cl::desc("Verbosity level"), + llvm::cl::init(false)); + +static llvm::cl::opt ParseOnly("parse-only", + llvm::cl::desc("Only parse the debug map, do " + "not actaully link the DWARF."), + llvm::cl::init(false)); + +int main(int argc, char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram StackPrinter(argc, argv); + llvm::llvm_shutdown_obj Shutdown; + + llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n"); + + llvm::MachODebugMapParser Parser(InputFile); + Parser.setPreprendPath(OsoPrependPath); + llvm::ErrorOr> DebugMap = Parser.parse(); + + if (auto EC = DebugMap.getError()) { + llvm::errs() << "error: cannot parse the debug map for \"" << InputFile << + "\": " << EC.message() << '\n'; + return 1; + } + + if (Verbose) + (*DebugMap)->print(llvm::outs()); + + if (ParseOnly) + return 0; + + llvm::DwarfLinker Linker(InputFile + ".dwarf"); + return !Linker.link(*DebugMap.get()); +} -- 2.34.1