blob: 0afccf42f6374cf3e617558ea9aa7b891a7fc1a6 [file] [log] [blame]
Eric Christopherb6174e32010-03-05 22:25:30 +00001//===- BuildLibCalls.cpp - Utility builder for libcalls -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements some functions that will create standard C libcalls.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Transforms/Utils/BuildLibCalls.h"
15#include "llvm/Type.h"
16#include "llvm/Constants.h"
17#include "llvm/Function.h"
18#include "llvm/Module.h"
19#include "llvm/Support/IRBuilder.h"
20#include "llvm/Target/TargetData.h"
21#include "llvm/LLVMContext.h"
22#include "llvm/Intrinsics.h"
23
24using namespace llvm;
25
26/// CastToCStr - Return V if it is an i8*, otherwise cast it to i8*.
27Value *llvm::CastToCStr(Value *V, IRBuilder<> &B) {
28 return B.CreateBitCast(V, B.getInt8PtrTy(), "cstr");
29}
30
31/// EmitStrLen - Emit a call to the strlen function to the builder, for the
32/// specified pointer. This always returns an integer value of size intptr_t.
33Value *llvm::EmitStrLen(Value *Ptr, IRBuilder<> &B, const TargetData *TD) {
34 Module *M = B.GetInsertBlock()->getParent()->getParent();
35 AttributeWithIndex AWI[2];
36 AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
37 AWI[1] = AttributeWithIndex::get(~0u, Attribute::ReadOnly |
38 Attribute::NoUnwind);
39
40 LLVMContext &Context = B.GetInsertBlock()->getContext();
41 Constant *StrLen = M->getOrInsertFunction("strlen", AttrListPtr::get(AWI, 2),
42 TD->getIntPtrType(Context),
43 B.getInt8PtrTy(),
44 NULL);
45 CallInst *CI = B.CreateCall(StrLen, CastToCStr(Ptr, B), "strlen");
46 if (const Function *F = dyn_cast<Function>(StrLen->stripPointerCasts()))
47 CI->setCallingConv(F->getCallingConv());
48
49 return CI;
50}
51
52/// EmitStrChr - Emit a call to the strchr function to the builder, for the
53/// specified pointer and character. Ptr is required to be some pointer type,
54/// and the return value has 'i8*' type.
55Value *llvm::EmitStrChr(Value *Ptr, char C, IRBuilder<> &B,
56 const TargetData *TD) {
57 Module *M = B.GetInsertBlock()->getParent()->getParent();
58 AttributeWithIndex AWI =
59 AttributeWithIndex::get(~0u, Attribute::ReadOnly | Attribute::NoUnwind);
60
61 const Type *I8Ptr = B.getInt8PtrTy();
62 const Type *I32Ty = B.getInt32Ty();
63 Constant *StrChr = M->getOrInsertFunction("strchr", AttrListPtr::get(&AWI, 1),
64 I8Ptr, I8Ptr, I32Ty, NULL);
65 CallInst *CI = B.CreateCall2(StrChr, CastToCStr(Ptr, B),
66 ConstantInt::get(I32Ty, C), "strchr");
67 if (const Function *F = dyn_cast<Function>(StrChr->stripPointerCasts()))
68 CI->setCallingConv(F->getCallingConv());
69 return CI;
70}
71
72/// EmitStrCpy - Emit a call to the strcpy function to the builder, for the
73/// specified pointer arguments.
74Value *llvm::EmitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B,
Benjamin Kramer7fa30b82010-03-11 20:45:13 +000075 const TargetData *TD, StringRef Name) {
Eric Christopherb6174e32010-03-05 22:25:30 +000076 Module *M = B.GetInsertBlock()->getParent()->getParent();
77 AttributeWithIndex AWI[2];
78 AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture);
79 AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
80 const Type *I8Ptr = B.getInt8PtrTy();
Benjamin Kramer7fa30b82010-03-11 20:45:13 +000081 Value *StrCpy = M->getOrInsertFunction(Name, AttrListPtr::get(AWI, 2),
Eric Christopherb6174e32010-03-05 22:25:30 +000082 I8Ptr, I8Ptr, I8Ptr, NULL);
83 CallInst *CI = B.CreateCall2(StrCpy, CastToCStr(Dst, B), CastToCStr(Src, B),
Benjamin Kramer7fa30b82010-03-11 20:45:13 +000084 Name);
Eric Christopherb6174e32010-03-05 22:25:30 +000085 if (const Function *F = dyn_cast<Function>(StrCpy->stripPointerCasts()))
86 CI->setCallingConv(F->getCallingConv());
87 return CI;
88}
89
Eric Christopherb0722af2010-03-11 17:45:38 +000090/// EmitStrNCpy - Emit a call to the strncpy function to the builder, for the
Eric Christopherbd973762010-03-11 01:25:07 +000091/// specified pointer arguments.
92Value *llvm::EmitStrNCpy(Value *Dst, Value *Src, Value *Len,
93 IRBuilder<> &B, const TargetData *TD) {
94 Module *M = B.GetInsertBlock()->getParent()->getParent();
95 AttributeWithIndex AWI[2];
96 AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture);
97 AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
98 const Type *I8Ptr = B.getInt8PtrTy();
99 Value *StrNCpy = M->getOrInsertFunction("strncpy", AttrListPtr::get(AWI, 2),
100 I8Ptr, I8Ptr, I8Ptr,
101 Len->getType(), NULL);
102 CallInst *CI = B.CreateCall3(StrNCpy, CastToCStr(Dst, B), CastToCStr(Src, B),
103 Len, "strncpy");
104 if (const Function *F = dyn_cast<Function>(StrNCpy->stripPointerCasts()))
105 CI->setCallingConv(F->getCallingConv());
106 return CI;
107}
108
109
Eric Christopherb6174e32010-03-05 22:25:30 +0000110/// EmitMemCpy - Emit a call to the memcpy function to the builder. This always
Evan Cheng0289b412010-03-23 15:48:04 +0000111/// expects that Len has type 'intptr_t' and Dst/Src are pointers.
Mon P Wange754d3f2010-04-02 18:43:02 +0000112Value *llvm::EmitMemCpy(Value *Dst, Value *Src, Value *Len,
113 unsigned Align, IRBuilder<> &B, const TargetData *TD) {
Eric Christopherb6174e32010-03-05 22:25:30 +0000114 Module *M = B.GetInsertBlock()->getParent()->getParent();
Mon P Wange754d3f2010-04-02 18:43:02 +0000115 const Type *Ty = Len->getType();
116 Value *MemCpy = Intrinsic::getDeclaration(M, Intrinsic::memcpy, &Ty, 1);
Eric Christopherb6174e32010-03-05 22:25:30 +0000117 Dst = CastToCStr(Dst, B);
118 Src = CastToCStr(Src, B);
Mon P Wange754d3f2010-04-02 18:43:02 +0000119 return B.CreateCall4(MemCpy, Dst, Src, Len,
120 ConstantInt::get(B.getInt32Ty(), Align));
Eric Christopherb6174e32010-03-05 22:25:30 +0000121}
122
Evan Cheng0289b412010-03-23 15:48:04 +0000123/// EmitMemCpyChk - Emit a call to the __memcpy_chk function to the builder.
124/// This expects that the Len and ObjSize have type 'intptr_t' and Dst/Src
125/// are pointers.
126Value *llvm::EmitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize,
127 IRBuilder<> &B, const TargetData *TD) {
128 Module *M = B.GetInsertBlock()->getParent()->getParent();
129 AttributeWithIndex AWI;
130 AWI = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
131 LLVMContext &Context = B.GetInsertBlock()->getContext();
132 Value *MemCpy = M->getOrInsertFunction("__memcpy_chk",
133 AttrListPtr::get(&AWI, 1),
134 B.getInt8PtrTy(),
135 B.getInt8PtrTy(),
136 B.getInt8PtrTy(),
137 TD->getIntPtrType(Context),
138 TD->getIntPtrType(Context), NULL);
139 Dst = CastToCStr(Dst, B);
140 Src = CastToCStr(Src, B);
141 CallInst *CI = B.CreateCall4(MemCpy, Dst, Src, Len, ObjSize);
142 if (const Function *F = dyn_cast<Function>(MemCpy->stripPointerCasts()))
143 CI->setCallingConv(F->getCallingConv());
144 return CI;
145}
146
Eric Christopherb6174e32010-03-05 22:25:30 +0000147/// EmitMemMove - Emit a call to the memmove function to the builder. This
148/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
Mon P Wange754d3f2010-04-02 18:43:02 +0000149Value *llvm::EmitMemMove(Value *Dst, Value *Src, Value *Len,
150 unsigned Align, IRBuilder<> &B, const TargetData *TD) {
Eric Christopherb6174e32010-03-05 22:25:30 +0000151 Module *M = B.GetInsertBlock()->getParent()->getParent();
152 LLVMContext &Context = B.GetInsertBlock()->getContext();
Mon P Wange754d3f2010-04-02 18:43:02 +0000153 const Type *Ty = TD->getIntPtrType(Context);
154 Value *MemMove = Intrinsic::getDeclaration(M, Intrinsic::memmove, &Ty, 1);
Eric Christopherb6174e32010-03-05 22:25:30 +0000155 Dst = CastToCStr(Dst, B);
156 Src = CastToCStr(Src, B);
157 Value *A = ConstantInt::get(B.getInt32Ty(), Align);
Mon P Wange754d3f2010-04-02 18:43:02 +0000158 return B.CreateCall4(MemMove, Dst, Src, Len, A);
Eric Christopherb6174e32010-03-05 22:25:30 +0000159}
160
161/// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is
162/// a pointer, Val is an i32 value, and Len is an 'intptr_t' value.
163Value *llvm::EmitMemChr(Value *Ptr, Value *Val,
164 Value *Len, IRBuilder<> &B, const TargetData *TD) {
165 Module *M = B.GetInsertBlock()->getParent()->getParent();
166 AttributeWithIndex AWI;
167 AWI = AttributeWithIndex::get(~0u, Attribute::ReadOnly | Attribute::NoUnwind);
168 LLVMContext &Context = B.GetInsertBlock()->getContext();
169 Value *MemChr = M->getOrInsertFunction("memchr", AttrListPtr::get(&AWI, 1),
170 B.getInt8PtrTy(),
171 B.getInt8PtrTy(),
172 B.getInt32Ty(),
173 TD->getIntPtrType(Context),
174 NULL);
175 CallInst *CI = B.CreateCall3(MemChr, CastToCStr(Ptr, B), Val, Len, "memchr");
176
177 if (const Function *F = dyn_cast<Function>(MemChr->stripPointerCasts()))
178 CI->setCallingConv(F->getCallingConv());
179
180 return CI;
181}
182
183/// EmitMemCmp - Emit a call to the memcmp function.
184Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2,
185 Value *Len, IRBuilder<> &B, const TargetData *TD) {
186 Module *M = B.GetInsertBlock()->getParent()->getParent();
187 AttributeWithIndex AWI[3];
188 AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
189 AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
190 AWI[2] = AttributeWithIndex::get(~0u, Attribute::ReadOnly |
191 Attribute::NoUnwind);
192
193 LLVMContext &Context = B.GetInsertBlock()->getContext();
194 Value *MemCmp = M->getOrInsertFunction("memcmp", AttrListPtr::get(AWI, 3),
195 B.getInt32Ty(),
196 B.getInt8PtrTy(),
197 B.getInt8PtrTy(),
198 TD->getIntPtrType(Context), NULL);
199 CallInst *CI = B.CreateCall3(MemCmp, CastToCStr(Ptr1, B), CastToCStr(Ptr2, B),
200 Len, "memcmp");
201
202 if (const Function *F = dyn_cast<Function>(MemCmp->stripPointerCasts()))
203 CI->setCallingConv(F->getCallingConv());
204
205 return CI;
206}
207
208/// EmitMemSet - Emit a call to the memset function
Mon P Wange754d3f2010-04-02 18:43:02 +0000209Value *llvm::EmitMemSet(Value *Dst, Value *Val,
210 Value *Len, IRBuilder<> &B, const TargetData *TD) {
Eric Christopherb6174e32010-03-05 22:25:30 +0000211 Module *M = B.GetInsertBlock()->getParent()->getParent();
212 Intrinsic::ID IID = Intrinsic::memset;
Mon P Wange754d3f2010-04-02 18:43:02 +0000213 const Type *Tys[1];
214 Tys[0] = Len->getType();
215 Value *MemSet = Intrinsic::getDeclaration(M, IID, Tys, 1);
Eric Christopherb6174e32010-03-05 22:25:30 +0000216 Value *Align = ConstantInt::get(B.getInt32Ty(), 1);
Mon P Wange754d3f2010-04-02 18:43:02 +0000217 return B.CreateCall4(MemSet, CastToCStr(Dst, B), Val, Len, Align);
Eric Christopherb6174e32010-03-05 22:25:30 +0000218}
219
220/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
221/// 'floor'). This function is known to take a single of type matching 'Op' and
222/// returns one value with the same type. If 'Op' is a long double, 'l' is
223/// added as the suffix of name, if 'Op' is a float, we add a 'f' suffix.
224Value *llvm::EmitUnaryFloatFnCall(Value *Op, const char *Name,
225 IRBuilder<> &B, const AttrListPtr &Attrs) {
226 char NameBuffer[20];
227 if (!Op->getType()->isDoubleTy()) {
228 // If we need to add a suffix, copy into NameBuffer.
229 unsigned NameLen = strlen(Name);
230 assert(NameLen < sizeof(NameBuffer)-2);
231 memcpy(NameBuffer, Name, NameLen);
232 if (Op->getType()->isFloatTy())
233 NameBuffer[NameLen] = 'f'; // floorf
234 else
235 NameBuffer[NameLen] = 'l'; // floorl
236 NameBuffer[NameLen+1] = 0;
237 Name = NameBuffer;
238 }
239
240 Module *M = B.GetInsertBlock()->getParent()->getParent();
241 Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
242 Op->getType(), NULL);
243 CallInst *CI = B.CreateCall(Callee, Op, Name);
244 CI->setAttributes(Attrs);
245 if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
246 CI->setCallingConv(F->getCallingConv());
247
248 return CI;
249}
250
251/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
252/// is an integer.
253Value *llvm::EmitPutChar(Value *Char, IRBuilder<> &B, const TargetData *TD) {
254 Module *M = B.GetInsertBlock()->getParent()->getParent();
255 Value *PutChar = M->getOrInsertFunction("putchar", B.getInt32Ty(),
256 B.getInt32Ty(), NULL);
257 CallInst *CI = B.CreateCall(PutChar,
258 B.CreateIntCast(Char,
259 B.getInt32Ty(),
260 /*isSigned*/true,
261 "chari"),
262 "putchar");
263
264 if (const Function *F = dyn_cast<Function>(PutChar->stripPointerCasts()))
265 CI->setCallingConv(F->getCallingConv());
266 return CI;
267}
268
269/// EmitPutS - Emit a call to the puts function. This assumes that Str is
270/// some pointer.
271void llvm::EmitPutS(Value *Str, IRBuilder<> &B, const TargetData *TD) {
272 Module *M = B.GetInsertBlock()->getParent()->getParent();
273 AttributeWithIndex AWI[2];
274 AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
275 AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
276
277 Value *PutS = M->getOrInsertFunction("puts", AttrListPtr::get(AWI, 2),
278 B.getInt32Ty(),
279 B.getInt8PtrTy(),
280 NULL);
281 CallInst *CI = B.CreateCall(PutS, CastToCStr(Str, B), "puts");
282 if (const Function *F = dyn_cast<Function>(PutS->stripPointerCasts()))
283 CI->setCallingConv(F->getCallingConv());
284
285}
286
287/// EmitFPutC - Emit a call to the fputc function. This assumes that Char is
288/// an integer and File is a pointer to FILE.
289void llvm::EmitFPutC(Value *Char, Value *File, IRBuilder<> &B,
290 const TargetData *TD) {
291 Module *M = B.GetInsertBlock()->getParent()->getParent();
292 AttributeWithIndex AWI[2];
293 AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture);
294 AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
295 Constant *F;
296 if (File->getType()->isPointerTy())
297 F = M->getOrInsertFunction("fputc", AttrListPtr::get(AWI, 2),
298 B.getInt32Ty(),
299 B.getInt32Ty(), File->getType(),
300 NULL);
301 else
302 F = M->getOrInsertFunction("fputc",
303 B.getInt32Ty(),
304 B.getInt32Ty(),
305 File->getType(), NULL);
306 Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/true,
307 "chari");
308 CallInst *CI = B.CreateCall2(F, Char, File, "fputc");
309
310 if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
311 CI->setCallingConv(Fn->getCallingConv());
312}
313
314/// EmitFPutS - Emit a call to the puts function. Str is required to be a
315/// pointer and File is a pointer to FILE.
316void llvm::EmitFPutS(Value *Str, Value *File, IRBuilder<> &B,
317 const TargetData *TD) {
318 Module *M = B.GetInsertBlock()->getParent()->getParent();
319 AttributeWithIndex AWI[3];
320 AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
321 AWI[1] = AttributeWithIndex::get(2, Attribute::NoCapture);
322 AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
323 Constant *F;
324 if (File->getType()->isPointerTy())
325 F = M->getOrInsertFunction("fputs", AttrListPtr::get(AWI, 3),
326 B.getInt32Ty(),
327 B.getInt8PtrTy(),
328 File->getType(), NULL);
329 else
330 F = M->getOrInsertFunction("fputs", B.getInt32Ty(),
331 B.getInt8PtrTy(),
332 File->getType(), NULL);
333 CallInst *CI = B.CreateCall2(F, CastToCStr(Str, B), File, "fputs");
334
335 if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
336 CI->setCallingConv(Fn->getCallingConv());
337}
338
339/// EmitFWrite - Emit a call to the fwrite function. This assumes that Ptr is
340/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
341void llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
342 IRBuilder<> &B, const TargetData *TD) {
343 Module *M = B.GetInsertBlock()->getParent()->getParent();
344 AttributeWithIndex AWI[3];
345 AWI[0] = AttributeWithIndex::get(1, Attribute::NoCapture);
346 AWI[1] = AttributeWithIndex::get(4, Attribute::NoCapture);
347 AWI[2] = AttributeWithIndex::get(~0u, Attribute::NoUnwind);
348 LLVMContext &Context = B.GetInsertBlock()->getContext();
349 Constant *F;
350 if (File->getType()->isPointerTy())
351 F = M->getOrInsertFunction("fwrite", AttrListPtr::get(AWI, 3),
352 TD->getIntPtrType(Context),
353 B.getInt8PtrTy(),
354 TD->getIntPtrType(Context),
355 TD->getIntPtrType(Context),
356 File->getType(), NULL);
357 else
358 F = M->getOrInsertFunction("fwrite", TD->getIntPtrType(Context),
359 B.getInt8PtrTy(),
360 TD->getIntPtrType(Context),
361 TD->getIntPtrType(Context),
362 File->getType(), NULL);
363 CallInst *CI = B.CreateCall4(F, CastToCStr(Ptr, B), Size,
364 ConstantInt::get(TD->getIntPtrType(Context), 1), File);
365
366 if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
367 CI->setCallingConv(Fn->getCallingConv());
368}
Benjamin Kramer0b6cb502010-03-12 09:27:41 +0000369
Benjamin Kramera30b1812010-03-12 20:41:29 +0000370SimplifyFortifiedLibCalls::~SimplifyFortifiedLibCalls() { }
371
Benjamin Kramer0b6cb502010-03-12 09:27:41 +0000372bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) {
373 this->CI = CI;
374 StringRef Name = CI->getCalledFunction()->getName();
375 BasicBlock *BB = CI->getParent();
376 IRBuilder<> B(CI->getParent()->getContext());
377
378 // Set the builder to the instruction after the call.
379 B.SetInsertPoint(BB, CI);
380
381 if (Name == "__memcpy_chk") {
382 if (isFoldable(4, 3, false)) {
383 EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
Mon P Wange754d3f2010-04-02 18:43:02 +0000384 1, B, TD);
Benjamin Kramer0b6cb502010-03-12 09:27:41 +0000385 replaceCall(CI->getOperand(1));
386 return true;
387 }
388 return false;
389 }
390
391 // Should be similar to memcpy.
392 if (Name == "__mempcpy_chk") {
393 return false;
394 }
395
396 if (Name == "__memmove_chk") {
397 if (isFoldable(4, 3, false)) {
398 EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
Mon P Wange754d3f2010-04-02 18:43:02 +0000399 1, B, TD);
Benjamin Kramer0b6cb502010-03-12 09:27:41 +0000400 replaceCall(CI->getOperand(1));
401 return true;
402 }
403 return false;
404 }
405
406 if (Name == "__memset_chk") {
407 if (isFoldable(4, 3, false)) {
408 Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(),
409 false);
Mon P Wange754d3f2010-04-02 18:43:02 +0000410 EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
Benjamin Kramer0b6cb502010-03-12 09:27:41 +0000411 replaceCall(CI->getOperand(1));
412 return true;
413 }
414 return false;
415 }
416
417 if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") {
418 // If a) we don't have any length information, or b) we know this will
419 // fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
420 // st[rp]cpy_chk call which may fail at runtime if the size is too long.
421 // TODO: It might be nice to get a maximum length out of the possible
422 // string lengths for varying.
423 if (isFoldable(3, 2, true)) {
424 Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD,
425 Name.substr(2, 6));
426 replaceCall(Ret);
427 return true;
428 }
429 return false;
430 }
431
432 if (Name == "__strncpy_chk") {
433 if (isFoldable(4, 3, false)) {
434 Value *Ret = EmitStrNCpy(CI->getOperand(1), CI->getOperand(2),
435 CI->getOperand(3), B, TD);
436 replaceCall(Ret);
437 return true;
438 }
439 return false;
440 }
441
442 if (Name == "__strcat_chk") {
443 return false;
444 }
445
446 if (Name == "__strncat_chk") {
447 return false;
448 }
449
450 return false;
451}